You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Pandas DataFrame的重复分组创建规则:保留最早记录并基于组内特征批量设置列值

解决Pandas分组保留最早记录并标记组内特征的问题

这问题我之前处理类似需求时碰到过,用Pandas的分组聚合功能就能轻松实现你的需求,给你两种可行的方案,适合不同的理解习惯:

方案一:一步聚合完成(高效简洁)

这种方法直接通过groupby+agg一步得到结果,代码量少,处理大型DataFrame时效率更高:

import pandas as pd

# 生成原DataFrame(和你的代码一致)
dates = pd.to_datetime(['2021-1-1', '2017-2-1', '2016-5-1', '2020-6-1', '2020-11-1', '2012-4-1'])
animals = pd.Series(['cat', 'dog', 'dog', 'cat', 'fish', 'fish'])
df = pd.DataFrame({'DoB' : dates, 'Animal' : animals})
df[r'Born in 2020?'] = df['DoB'].apply(lambda x: x.year == 2020)

# 核心处理代码
result_df = df.groupby('Animal').agg(
    DoB=('DoB', 'min'),  # 取每组最早的出生日期
    'Duplicate born in 2020?'=('Born in 2020?', 'any')  # 判断组内是否有2020年出生的记录
).reset_index()

# 调整列顺序和示例输出一致
result_df = result_df[['DoB', 'Animal', 'Duplicate born in 2020?']]
print(result_df)

代码解释:

  • groupby('Animal'):按动物种类对DataFrame分组
  • agg():聚合操作,同时完成两个任务:
    • ('DoB', 'min'):对每个组的DoB列取最小值,即该动物的最早出生日期
    • ('Born in 2020?', 'any'):对每个组的布尔列用any()判断,只要组内有一条记录为True,结果就为True
  • reset_index():把Animal从分组索引变回普通列,保证结构和需求一致

方案二:分步处理(逻辑清晰)

如果觉得一步聚合有点抽象,也可以拆成分步骤执行,逻辑更直观:

import pandas as pd

# 生成原DataFrame
dates = pd.to_datetime(['2021-1-1', '2017-2-1', '2016-5-1', '2020-6-1', '2020-11-1', '2012-4-1'])
animals = pd.Series(['cat', 'dog', 'dog', 'cat', 'fish', 'fish'])
df = pd.DataFrame({'DoB' : dates, 'Animal' : animals})
df[r'Born in 2020?'] = df['DoB'].apply(lambda x: x.year == 2020)

# 步骤1:标记每组中最早的记录
df['is_earliest'] = df.groupby('Animal')['DoB'].transform(lambda x: x == x.min())

# 步骤2:计算每个动物组的"是否有2020年出生记录"标记
group_flag = df.groupby('Animal')['Born in 2020?'].any().reset_index(name='Duplicate born in 2020?')

# 步骤3:筛选最早记录并合并标记
result_df = df[df['is_earliest']].merge(group_flag, on='Animal')

# 步骤4:删除不需要的列并调整顺序
result_df = result_df.drop(columns=['Born in 2020?', 'is_earliest'])[['DoB', 'Animal', 'Duplicate born in 2020?']]
print(result_df)

代码解释:

  • transform(lambda x: x == x.min()):给每组中最早的记录标记为True,其他为False
  • groupby('Animal')['Born in 2020?'].any():单独计算每个组的标记结果
  • merge(group_flag, on='Animal'):把标记结果合并到筛选出的最早记录行中
  • 最后清理多余列,调整列顺序到需求格式

两种方案运行后都会得到你期望的结果:

DoBAnimalDuplicate born in 2020?
02020-06-01catTrue
12016-05-01dogFalse
22012-04-01fishTrue

内容的提问来源于stack exchange,提问作者George

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 14:18:12