如何用groupby替代低效for循环为各子组分数应用不同函数?
用Pandas GroupBy实现分组自定义聚合的高效方案
兄弟,我太懂你大数据集用for循环慢到崩溃的痛苦了!直接用Pandas的groupby结合自定义逻辑就能高效解决,彻底告别低效循环。下面给你两种实用的方案,看你的需求灵活选择:
核心思路
我们可以先按person_id和group_id做双层分组,然后针对不同group_id对应的分组,给score列应用不同的聚合函数——全程都是Pandas底层优化过的操作,效率拉满。
方法一:自定义聚合函数(灵活适配复杂逻辑)
如果你的聚合逻辑比较特殊(比如不是Pandas内置函数),用groupby.apply()结合条件判断就很合适。举个例子:假设group_id=0时求均值,group_id=1时求和,group_id=2时取最大值:
import pandas as pd # 构造示例数据(模拟你的数据集结构) df = pd.DataFrame({ 'person_id': [1,1,1,2,2,3], 'group_id': [0,1,2,0,1,0], 'score': [80,90,75,85,95,70] }) def custom_agg(group): # 拿到当前分组的group_id值(因为是按group_id分的组,所以整个组的group_id是一致的) current_group = group['group_id'].iloc[0] if current_group == 0: return group['score'].mean() elif current_group == 1: return group['score'].sum() elif current_group == 2: return group['score'].max() else: # 处理其他未定义的group_id,比如返回空值 return pd.NA # 执行分组聚合,最后重置索引得到规整的结果 result = df.groupby(['person_id', 'group_id']).apply(custom_agg).reset_index(name='agg_score') print(result)
运行后会得到这样的结果:
person_id group_id agg_score 0 1 0 80.0 1 1 1 90.0 2 1 2 75.0 3 2 0 85.0 4 2 1 95.0 5 3 0 70.0
方法二:字典映射聚合(简洁高效,适合内置函数)
如果你的聚合函数都是Pandas内置的(比如mean、sum、max这些),用字典映射的方式更简洁,效率也更高:
# 先定义group_id到聚合函数的映射关系 agg_mapping = { 0: 'mean', 1: 'sum', 2: 'max' } # 分组后对score列应用对应函数 # x.name[1]获取分组键中的group_id值,然后从映射中拿到对应的聚合函数 result = df.groupby(['person_id', 'group_id'])['score'].agg( lambda x: getattr(x, agg_mapping[x.name[1]])() ).reset_index(name='agg_score')
这里用getattr(x, agg_mapping[x.name[1]])()是为了把函数名字符串转成实际的方法调用,比直接写判断更简洁。
为什么这比for循环高效?
Pandas的groupby底层是用C语言优化实现的,避免了Python层面循环的巨大开销,在大数据集(比如百万级以上数据)下,速度能比for循环快几十甚至上百倍,完全不用再担心程序卡壳。
内容的提问来源于stack exchange,提问作者Eyal S.
相关产品推荐
相关产品推荐

