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

如何在Pandas链式groupby-agg中基于当前索引分组(排除指定列)

解决方案

方法1:使用pipe动态生成分组级别列表

通过pipe将当前Series/DataFrame传入lambda函数,自动生成排除指定级别的索引名称列表,无需手动重复编写分组键:

import random
import pandas as pd

data = pd.DataFrame({
    "name" : random.choices(["N1", "N2", "N3"], k=100),
    "part" : random.choices(["P1", "P2", "P3"], k=100),
    "sub" : random.choices(["S1", "S2", "S3"], k=100),
    "val" : range(100),
})

result = (
    data
    .groupby(["name", "part", "sub"])["val"].mean()
    # 排除sub级别,按剩余索引分组
    .pipe(lambda s: s.groupby([name for name in s.index.names if name != "sub"]))
    .agg(["mean", "std"])
    # 排除part级别,按剩余索引分组
    .pipe(lambda s: s.groupby([name for name in s.index.names if name != "part"]))
    .mean()
)

方法2:自定义辅助函数,简化链式调用

如果需要多次使用排除指定级别的分组逻辑,可以封装成辅助函数,让代码更贴近你想要的current_index_but('sub')风格:

def groupby_exclude(obj, exclude_level):
    """按当前多级索引排除指定级别后分组"""
    keep_levels = [name for name in obj.index.names if name != exclude_level]
    return obj.groupby(keep_levels)

result = (
    data
    .groupby(["name", "part", "sub"])["val"].mean()
    .pipe(groupby_exclude, "sub")
    .agg(["mean", "std"])
    .pipe(groupby_exclude, "part")
    .mean()
)

方法3:结合reset_index与当前索引分组

利用reset_index移除指定索引级别(保留其余索引),直接按剩余索引分组,无需手动指定分组键:

result = (
    data
    .groupby(["name", "part", "sub"])["val"].mean()
    # 移除sub索引级别,剩余索引为name、part
    .reset_index("sub", drop=True)
    .groupby(level=list(range(len(_.index.names))))
    .agg(["mean", "std"])
    # 移除part索引级别,剩余索引为name
    .reset_index("part", drop=True)
    .groupby(level=0)
    .mean()
)

关键说明

  • Pandas的groupby传入索引名称列表时,会直接按这些索引级别分组,这是实现动态分组的核心逻辑。
  • 不要在groupby中直接使用作用于单个索引元素的lambda函数,这类函数是对每个索引标签做转换,而非选择索引级别。
  • 若在IPython/Jupyter环境中,可直接用_指代当前链式中的对象,简化写法:.groupby([name for name in _.index.names if name != "sub"]),但此写法不适用于普通脚本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 12:20:32