如何在Pandas中使用groupby时获取与聚合字段匹配的非聚合列?
如何在Pandas中使用groupby时获取与聚合字段匹配的非聚合列?
这个需求我之前也碰到过,其实核心就是找到每个分组中对应max(subid)的那一行,把它的reason和record和你的聚合结果关联起来就行,给你两种可行的方法:
方法一:先聚合,再关联匹配行(推荐,性能更优)
这种方法把聚合和匹配分开处理,逻辑清晰而且在数据量大的时候性能更好。
首先,先构造你的原始测试数据(方便你直接运行测试):
import pandas as pd data = { 'Id': [100, 100, 100, 101, 101], 'application': ['app_1', 'app_2', 'app_3', 'app_1', 'app_2'], 'is_a': [False, True, True, False, True], 'is_b': [False, False, True, False, False], 'is_c': [False, False, False, False, False], 'reason': ['test1', 'test2', 'test3', 'test1', 'test2'], 'subid': [4, 3, 5, 3, 4], 'record': ['record100', 'record100', 'record100', 'record101', 'record101'] } df = pd.DataFrame(data)
第一步,先完成你原本需要的聚合操作:
# 执行基础聚合,得到你已经有的结果 agg_df = df.groupby('Id').agg( application=('application', ', '.join), is_a=('is_a', 'max'), is_b=('is_b', 'max'), is_c=('is_c', 'max'), subid=('subid', 'max') ).reset_index()
第二步,找到每个Id分组中subid最大的那一行,提取对应的reason和record:
# 用idxmax获取每个组中subid最大的行的索引,再提取需要的列 match_df = df.loc[df.groupby('Id')['subid'].idxmax(), ['Id', 'reason', 'record']]
第三步,把聚合结果和匹配到的列合并,就得到你想要的最终结果了:
# 按Id合并两个DataFrame final_df = pd.merge(agg_df, match_df, on='Id', how='left')
运行后final_df就是你期望的输出格式啦。
方法二:分组时用自定义函数一次性处理
如果觉得分开写麻烦,也可以用自定义函数在分组时一次性完成所有操作,代码更紧凑,不过数据量大的时候性能会比方法一稍差:
def process_group(group): # 拼接application字段 app_combined = ', '.join(group['application']) # 计算is_开头列的最大值 is_a_max = group['is_a'].max() is_b_max = group['is_b'].max() is_c_max = group['is_c'].max() # 找到当前组中subid最大的行 max_sub_row = group.loc[group['subid'].idxmax()] # 返回所有需要的字段 return pd.Series({ 'application': app_combined, 'is_a': is_a_max, 'is_b': is_b_max, 'is_c': is_c_max, 'subid': max_sub_row['subid'], 'reason': max_sub_row['reason'], 'record': max_sub_row['record'] }) # 应用自定义分组函数 final_df = df.groupby('Id').apply(process_group).reset_index()
小提醒
如果你的分组中存在多个行的subid都是最大值,idxmax会返回第一个出现的那一行的索引。如果需要处理这种多最大值的情况,可以根据你的需求调整逻辑(比如拼接所有对应的reason),不过看你的示例数据,每个组只有一个max subid的行,所以这个方法完全适用。
内容来源于stack exchange




