如何将完整的GroupBy分组对象传入自定义函数并生成结果列
问题:Pandas分组后将自定义函数应用于完整分组DataFrame并填充结果列
我有一个结构如下的Pandas DataFrame:
import pandas as pd data = { 'date': ['2022/03/01']*3 + ['2022/03/02']*3 + ['2022/03/03']*3, 'col1': [1,3,5,6,2,8,2,10,9], 'col2': [5,6,7,8,9,10,11,12,13], 'col3': [10,12,14,15,17,19,21,22,23] } df = pd.DataFrame(data)
我定义了一个自定义函数,它接收一个完整的DataFrame,执行计算后返回单个float结果:
def my_func(df): # 示例:计算分组内col1、col2、col3的总和(实际逻辑可自定义) return df[['col1','col2','col3']].sum().sum()
我的需求是:按date列分组,把每个完整的分组DataFrame传入my_func,然后将函数返回的结果填充到该分组的所有行中,最终得到带result列的DataFrame(每个日期分组的所有行对应同一个result值)。
我尝试用df["result"] = df.groupby(["date"]).transform(my_func)实现,但发现传入my_func的不是完整的分组DataFrame,而是分组的每一列数据,请问该怎么正确实现?
解决方案
你遇到的问题是因为transform的设计逻辑:它默认会逐列处理分组数据,把每个分组的单独一列传给函数,而不是整个分组的DataFrame。要实现你的需求,我们可以用groupby.apply()先计算每个分组的结果,再把结果映射回原DataFrame的每一行。
方法一:用apply生成分组结果,再通过map填充
# 第一步:对每个完整分组DataFrame应用my_func,得到日期对应结果的Series group_results = df.groupby('date').apply(my_func) # 第二步:用map把每个日期对应的结果填充到原DataFrame的每一行 df['result'] = df['date'].map(group_results)
方法二:用apply生成结果后,通过merge合并(更直观)
如果你觉得map不够直观,也可以把分组结果转成DataFrame,再和原表合并:
# 生成分组结果并转成带列名的DataFrame result_df = df.groupby('date').apply(my_func).reset_index(name='result') # 左连接合并,把结果填充到对应日期的所有行 df = df.merge(result_df, on='date', how='left')
为什么这两种方法可行?
groupby.apply()会把每个完整的分组DataFrame作为参数传给my_func,函数返回的单个值会被整理成以date为索引的Series(或转成DataFrame)。- 之后通过
map或merge,我们把每个日期对应的结果匹配到原表的每一行,实现同一个分组的所有行共享同一个result值的效果。
比如用示例中的my_func(计算分组所有数值列的总和),最终的result列会是:
- 2022/03/01对应
1+5+10+3+6+12+5+7+14=63 - 2022/03/02对应
6+8+15+2+9+17+8+10+19=94 - 2022/03/03对应
2+11+21+10+12+22+9+13+23=123
完全符合你的需求。
内容的提问来源于stack exchange,提问作者Denver Dang
相关产品推荐
相关产品推荐

