
本文详解如何基于某一列(如类别列 b)对 dataframe 分组,并保留每组中日期列(a)最新(最大)对应的那一整行记录,适用于去重、时间维度聚合等典型数据分析场景。
本文详解如何基于某一列(如类别列 b)对 dataframe 分组,并保留每组中日期列(a)最新(最大)对应的那一整行记录,适用于去重、时间维度聚合等典型数据分析场景。
在实际数据分析中,我们常遇到这样的需求:一个 DataFrame 包含重复的分类标识(如商品名称、用户 ID、地区代码等),而每条记录附带一个时间戳(如订单日期、更新时间)。此时,若只需为每个分类保留最新一条记录(即该分类下日期最大的那行),就不能简单调用 .max() 获取标量结果——而是要完整保留对应原始行的所有字段。
以示例数据为例:
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 当前是字符串格式,直接 .max() 会按字典序比较(如 '26/12/2023' > '26/12/2022' 成立,但不可靠),因此必须先转换为 datetime 类型,确保时间逻辑正确:
df['A'] = pd.to_datetime(df['A'], dayfirst=True) # 指定 dayfirst=True 适配 DD/MM/YYYY 格式
✅ 正确做法是使用 df.sort_values().drop_duplicates() 或 df.groupby().idxmax() —— 后者更高效且语义清晰:
✅ 推荐方案:groupby().idxmax() + .loc
# 获取每组 B 中 A 值最大(即最新)所在行的索引
idx = df.groupby('B')['A'].idxmax()
# 用这些索引定位原 DataFrame 的完整行
result = df.loc[idx].sort_index() # sort_index() 可选,用于按原始顺序整理输出? idxmax() 返回的是原始索引值(而非位置序号),因此配合 .loc 能精准提取整行,包括所有列(A、B、E 等),完美匹配题目要求。
? 运行结果验证(已转为 datetime 后):
| A | B | E |
|---|---|---|
| 2023-12-26 | apple | 7,9 |
| 2023-12-26 | pear | 28,6 |
| 2022-12-26 | orange | 33,3 |
| 2023-12-26 | wildberry | 24,7 |
| 2023-12-26 | grapes | 17,1 |
(注意:orange 只有一条记录,故自动保留;apple 和 wildberry 均取 2023 年版本)
⚠️ 常见误区提醒:
- ❌ df.groupby('B')['A'].max() 只返回 Series(B → 最大日期),丢失其他列信息,无法直接得到完整行;
- ❌ 直接 df.groupby('B').max() 对非数值列(如 E 列含逗号数字)可能报错或行为异常(默认对所有列取 max,字符串列取字典最大值);
- ❌ 忘记日期类型转换,会导致 '26/12/2022' > '01/01/2023' 判定错误(字符串比较)。
✅ 替代方案(适合初学者理解):排序 + 去重
result = df.sort_values('A', ascending=False).drop_duplicates(subset='B', keep='first')先按日期降序排列,再对 B 列去重并保留首次出现(即最新日期行)。逻辑直观,但性能略低于 idxmax(尤其大数据集)。
? 总结
- 核心思路:先确保日期列为 datetime 类型 → 用 groupby('B')['A'].idxmax() 获取关键索引 → .loc 提取完整行;
- 该方法兼具准确性、可读性与执行效率,是 Pandas 时间维度去重的标准实践;
- 初学者可优先掌握 idxmax + loc 组合,它比嵌套 loc 条件筛选更简洁、不易出错。
如需进一步扩展(如同时保留多个时间列的最大值、处理空值或并列最大值),可结合 na_position='last' 或 keep='all' 参数灵活调整。










