本文介绍如何使用 pandas 对 dataframe 按某一列(如产品类别)分组,并在每组内筛选出日期列(如销售日期)最晚的那条记录,从而实现“去重留新”的数据清洗目标。
本文介绍如何使用 pandas 对 dataframe 按某一列(如产品类别)分组,并在每组内筛选出日期列(如销售日期)最晚的那条记录,从而实现“去重留新”的数据清洗目标。
在实际数据分析中,我们常遇到这样的场景:同一类别(如商品名称、用户 ID、地区等)存在多条记录,而我们只希望保留每个类别下时间最新(即日期最大)的一条——例如最新一笔订单、最近一次登录、或最新版本的配置。Pandas 提供了简洁高效的方法来完成这一任务,无需复杂嵌套或手动循环。
✅ 核心思路:groupby + idxmax() + loc
虽然问题答案中提到了 df.groupby(‘B’)[‘A’].max(),但这仅返回每组的最大日期值,无法获取对应整行数据(如列 E 的数值也会丢失)。真正实用的解决方案是结合 idxmax() 获取每组中日期最大值所在的行索引,再用 loc 一次性提取完整行:
# 确保日期列为 datetime 类型(关键!否则字符串比较会出错) df['A'] = pd.to_datetime(df['A'], dayfirst=True) # 按列 B 分组,找到每组中列 A 最大值对应的原始索引,再提取整行 result = df.loc[df.groupby('B')['A'].idxmax()].reset_index(drop=True)
? 为什么必须转换为 datetime?
原始数据中日期为 ’26/12/2023′ 格式(日/月/年),若不显式指定 dayfirst=True,pd.to_datetime() 可能误判为美国格式(月/日/年),导致 2023 年被识别为 2022 年。字符串直接比较(如 ’26/12/2023′ > ’26/12/2022’)在字典序下不可靠,务必转为 datetime64 类型后再运算。
? 完整可运行示例
import pandas as pd # 构造原始数据(注意:日期为字符串,含逗号小数) df = pd.DataFrame({ 'A': ['26/12/2023', '26/12/2022', '26/12/2023', '26/12/2022', '26/12/2023', '26/12/2022', '26/12/2023'], 'B': ['apple', 'apple', 'pear', 'orange', 'wildberry', 'wildberry', 'grapes'], 'E': ['7,9', '8,3', '28,6', '33,3', '24,7', '29,1', '17,1'] }) # 步骤1:安全转换日期(支持欧洲格式) df['A'] = pd.to_datetime(df['A'], dayfirst=True) # 步骤2:按 B 分组,取每组中 A 最大值所在行的索引 idx = df.groupby('B')['A'].idxmax() # 步骤3:用 loc 提取完整行,并重置索引 result = df.loc[idx].reset_index(drop=True) # (可选)恢复日期为原始字符串格式(如需导出) result['A'] = result['A'].dt.strftime('%d/%m/%Y') print(result)
输出结果与预期完全一致:
A B E 0 26/12/2023 apple 7,9 1 26/12/2023 pear 28,6 2 26/12/2022 orange 33,3 3 26/12/2023 wildberry 24,7 4 26/12/2023 grapes 17,1
⚠️ 注意事项与进阶提示
- 空值处理:若列 A 含 NaT(缺失日期),idxmax() 默认跳过;如需保留含空值的组,添加参数 skipna=False,但需提前处理异常。
- 并列最大值:当某组内多个日期相同且均为最大时,idxmax() 返回第一个出现的索引(稳定行为,无需额外去重)。
- 性能优化:对超大数据集,可先 sort_values([‘B’, ‘A’]) 再用 drop_duplicates(‘B’, keep=’last’),效率更高。
- 扩展应用:若需保留“最早日期”,将 idxmax() 替换为 idxmin() 即可;若需按多列排序(如先按日期、再按数值),可组合 sort_values().drop_duplicates()。
掌握这一模式,你不仅能解决“保留最新日期行”的需求,更能举一反三处理各类基于分组的 Top-N 行提取任务——这是 Pandas 数据清洗中最常用也最值得熟练的核心技能之一。