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

如何确保Pandas中Series分组聚合操作保留原列名?

Pandas单列GroupBy聚合保留原列名的实现方案

场景背景

工作中要求所有GroupBy操作不得丢失原列信息,但直接对单列执行聚合时,结果会丢失原列名:

df.groupby('A')['B'].agg(['max','min'])
# 结果
   max  min
A          
a    6    1
b    5    2
c    7    3

而选择多列聚合或把单列转为列表形式(df.groupby('A')[['B']].agg(['max','min']))时,会生成包含原列名的多级索引,但受工作限制无法强制使用列表形式选择列,因此需要通过Pandas设置或重写函数实现自动保留原列名。

可行解决方案

1. 重写SeriesGroupBy的agg方法(推荐)

直接修改Pandas的SeriesGroupBy类的agg方法,让它在处理多函数聚合时自动添加原列名作为多级索引的第一级:

import pandas as pd
from pandas.core.groupby.generic import SeriesGroupBy

# 保存原agg方法,方便后续恢复
original_agg = SeriesGroupBy.agg

def custom_agg(self, func, *args, **kwargs):
    result = original_agg(self, func, *args, **kwargs)
    # 仅处理传入聚合函数列表且返回DataFrame的情况
    if isinstance(func, list) and isinstance(result, pd.DataFrame):
        col_name = self.obj.name
        # 构造多级列索引
        result.columns = pd.MultiIndex.from_product([[col_name], result.columns])
    return result

# 替换原方法
SeriesGroupBy.agg = custom_agg

修改后执行原代码,会自动生成带原列名的多级索引:

df.groupby('A')['B'].agg(['max','min'])
# 结果
    B    
  max min
A        
a   6   1
b   5   2
c   7   3

注意:重写内置方法可能影响其他业务代码,建议在特定业务模块中使用,使用完成后可恢复原方法:

SeriesGroupBy.agg = original_agg

2. 使用命名聚合显式指定列名

如果不想修改内置方法,可以用命名聚合显式生成带原列名的复合列名:

df.groupby('A')['B'].agg(B_max='max', B_min='min')
# 结果
   B_max  B_min
A              
a      6      1
b      5      2
c      7      3

这种方式无需修改Pandas源码,但需要手动拼接列名,适合零散场景使用。

3. 自定义apply聚合函数

通过apply封装聚合逻辑,自动添加原列名:

def agg_with_colname(funcs):
    def wrapper(series):
        agg_result = series.agg(funcs)
        # 把原列名作为索引第一级
        agg_result.index = pd.MultiIndex.from_product([[series.name], agg_result.index])
        return agg_result
    return wrapper

# 使用方式
df.groupby('A')['B'].apply(agg_with_colname(['max','min'])).unstack()

该方法灵活性高,但性能略低于直接使用agg方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 11:57:26