如何高效实现Pandas DataFrame多列多维度聚合与宽表转换?
高效实现Pandas DataFrame的多维度聚合与列重塑
嘿,我来帮你简化这个数据整理的流程!你之前多次创建pivot再合并的方式确实有点重复繁琐,其实我们可以用一次分组聚合+列名重塑的方式搞定,代码更简洁,运行效率也更高。
核心实现方法(推荐)
这种方法通过pivot_table一次性完成年度维度的聚合,再合并全局统计结果,步骤清晰且高效:
import pandas as pd # 你的原始数据 data = {'id':[101,101,101,101,102,102,102,102], 'day':[1,2,1,2,1,2,1,2], 'year':[2011,2011,2012,2012,2011,2011,2012,2012], 'avg':[0.500,0.400,0.300,0.200,0.555,0.455,0.355,0.255], 'sum':[1, 2, 2, 3, 6, 6, 8, 9], 'div':[2, 1, 3, 2, 6, 1, 6, 3]} df = pd.DataFrame(data) # 1. 计算每个id的全局sum和div总和 global_stats = df.groupby('id')[['sum', 'div']].sum().reset_index() # 2. 按id+year聚合,针对不同列设置对应聚合规则 yearly_stats = df.pivot_table( index='id', columns='year', aggfunc={ 'avg': 'mean', # 按年份计算avg的平均值 'sum': 'sum', # 按年份计算sum的总和 'div': 'mean' # 按年份计算div的平均值(可根据需求调整) } ) # 3. 重塑列名为「年份_列名」格式 yearly_stats.columns = [f'{year}_{col}' for col, year in yearly_stats.columns] # 4. 合并结果并调整列顺序 result = global_stats.merge(yearly_stats, on='id')[ ['id', 'sum', 'div', '2011_avg', '2012_avg', '2011_sum', '2012_sum', '2011_div', '2012_div'] ] print(result)
运行后输出:
id sum div 2011_avg 2012_avg 2011_sum 2012_sum 2011_div 2012_div 0 101 8 8 0.45 0.25 3 5 1.5 2.5 1 102 29 16 0.505 0.305 12 17 3.5 4.5
注:如果你的
div列需要其他聚合规则(比如取特定day的值、总和等),只需要修改aggfunc中div对应的函数即可,灵活性很强。
更紧凑的写法(一次groupby搞定)
如果你想把所有聚合逻辑放在一次操作里,可以用groupby+agg结合嵌套展开的方式:
import pandas as pd data = {'id':[101,101,101,101,102,102,102,102], 'day':[1,2,1,2,1,2,1,2], 'year':[2011,2011,2012,2012,2011,2011,2012,2012], 'avg':[0.500,0.400,0.300,0.200,0.555,0.455,0.355,0.255], 'sum':[1, 2, 2, 3, 6, 6, 8, 9], 'div':[2, 1, 3, 2, 6, 1, 6, 3]} df = pd.DataFrame(data) # 一次完成全局+年度聚合 agg_result = df.groupby('id').agg( sum=('sum', 'sum'), div=('div', 'sum'), avg_year=('avg', lambda x: x.groupby(df['year']).mean()), sum_year=('sum', lambda x: x.groupby(df['year']).sum()), div_year=('div', lambda x: x.groupby(df['year']).mean()) ) # 展开嵌套的年度统计列并命名 agg_result = agg_result.join( pd.concat( [agg_result[col].apply(pd.Series) for col in ['avg_year', 'sum_year', 'div_year']], axis=1 ) ).drop(['avg_year', 'sum_year', 'div_year'], axis=1) agg_result.columns = ['sum', 'div', '2011_avg', '2012_avg', '2011_sum', '2012_sum', '2011_div', '2012_div'] agg_result.reset_index(inplace=True) print(agg_result)
这两种方法都避免了多次pivot和合并的冗余操作,在数据量较大时能显著提升运行效率,代码也更易维护。
内容的提问来源于stack exchange,提问作者YilGuk Seo
相关产品推荐
相关产品推荐

