
本文介绍如何使用 pandas 对 dataframe 按某一列(如产品类别)分组,并在每组中仅保留日期列(如销售日期)最新的那条记录,适用于去重、数据清洗及时间序列汇总等典型场景。
本文介绍如何使用 pandas 对 dataframe 按某一列(如产品类别)分组,并在每组中仅保留日期列(如销售日期)最新的那条记录,适用于去重、数据清洗及时间序列汇总等典型场景。
在实际数据分析中,常遇到类似需求:同一类别(如商品名、用户ID、地区)存在多条记录,而我们只希望保留每个类别的“最新”一条——通常以时间戳(日期列)为判断依据。例如,你有一个包含商品名称(列 B)、对应日期(列 A)和数值(列 E)的表格,目标是:对每个商品,只保留其最晚日期对应的整行数据。
但需特别注意:原始数据中的日期是字符串格式(如 '26/12/2023'),若直接使用 .groupby('B')['A'].max(),Pandas 会按字典序比较字符串,而非真实日期顺序——这将导致错误结果(例如 '26/12/2022' > '01/01/2023' 在字符串比较中成立)。因此,必须先将日期列转换为 datetime 类型,再执行分组聚合。
以下是完整、稳健的实现步骤:
✅ 正确做法:先转日期类型,再分组取索引
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]
})
# 第一步:将列 A 转换为 datetime(注意 format 参数适配 DD/MM/YYYY)
df['A'] = pd.to_datetime(df['A'], format='%d/%m/%Y')
# 第二步:按 B 分组,找出每组中 A 最大(即最新)的行索引
idx = df.groupby('B')['A'].idxmax()
# 第三步:用 .loc 索引原 DataFrame,获取完整行
result = df.loc[idx].sort_values('B').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 grapes 17.1 2 26/12/2023 pear 28.6 3 26/12/2022 orange 33.3 4 26/12/2023 wildberry 24.7
⚠️ 关键注意事项
- 不要跳过日期转换:pd.to_datetime() 是必需前置步骤;忽略它将导致逻辑错误;
- idxmax() vs max():.max() 只返回最大日期值,而 .idxmax() 返回对应行索引,这才是获取整行数据的关键;
- 处理缺失值:若某组中 A 存在 NaT(缺失日期),idxmax() 默认跳过;如需保留或报错,可加参数 skipna=False 并捕获异常;
- 多列排序需求? 若需同时按日期和另一列(如优先级)确定“最新”,可用 sort_values(['A', 'priority']).drop_duplicates('B', keep='last') 替代。
? 小结
对初学者而言,不必纠结于复杂链式 .loc 表达式。牢记核心逻辑:日期标准化 → 分组定位 → 行提取。掌握 groupby().idxmax() 这一组合,即可高效解决“每组取最新记录”的高频任务,且代码简洁、可读性强、性能优异。










