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

如何在三级MultiIndex的DataFrame中筛选col0均值最小的行

三级MultiIndex DataFrame分组筛选优化方案

问题背景

给定三级MultiIndex的DataFrame:

import pandas as pd

df = pd.DataFrame({
    'col0': [0,8,3,1,2,2,0,0],
    'col1': range(8),
}, index=pd.MultiIndex.from_product([[0,1]] * 3, names=['idx0', 'idx1', 'idx2']))

数据展示:

col0  col1
idx0 idx1 idx2            
0    0    0        0     0
          1        8     1
     1    0        3     2
          1        1     3
1    0    0        2     4
          1        2     5
     1    0        0     6
          1        0     7

需求:针对每个idx0,找到col0均值最小的idx1,筛选原DataFrame中匹配这些(idx0, idx1)对的所有行,预期结果:

col0  col1
idx0 idx1 idx2            
0    1    0        3     2
          1        1     3
1    1    0        0     6
          1        0     7

现有方案及问题

已完成前两步计算:

  1. 按idx0、idx1分组计算col0均值:
mean_col0 = df.groupby(['idx0', 'idx1'])['col0'].mean()

输出:

idx0  idx1
0     0       4.0
      1       2.0
1     0       2.0
      1       0.0
  1. 按idx0分组选出均值最小的idx1对应索引:
level_idxs = mean_col0.groupby('idx0').idxmin()

输出:

idx0
0    (0, 1)
1    (1, 1)

第三步筛选时,直接用df.loc[level_idxs]会因索引形状不匹配报错,现有解决方案为:

result = df[df.index.droplevel(2).isin(level_idxs)]

但该方法较为繁琐,以下是更优实现方式:


更优实现方案

方案一:利用pd.IndexSlice直接切片

借助pandas的IndexSlice工具,可直接基于level_idxs中的元组对多级索引进行切片,无需处理索引层级:

import pandas as pd

mean_col0 = df.groupby(['idx0', 'idx1'])['col0'].mean()
level_idxs = mean_col0.groupby('idx0').idxmin()

# 使用IndexSlice匹配所有(idx0, idx1)对对应的idx2行
result = df.loc[pd.IndexSlice[level_idxs, :], :]

优势:完全复用已计算的level_idxs,代码简洁直观,直接通过索引切片完成筛选,避免额外的索引转换操作。

方案二:用transform一步完成标记与筛选

无需生成中间均值Series,直接在原DataFrame上通过transform广播组内均值,再筛选出符合条件的行:

# 计算每个(idx0, idx1)组的col0均值,广播到每行
group_mean = df.groupby(['idx0', 'idx1'])['col0'].transform('mean')
# 计算每个idx0组内的最小均值,广播到每行
min_group_mean = df.groupby('idx0')['col0'].transform(
    lambda x: x.groupby(df.index.get_level_values('idx1')).mean().min()
)
# 筛选均值等于对应idx0组内最小均值的行
result = df[group_mean == min_group_mean]

优势:全程在原DataFrame上操作,无需额外存储中间结果,逻辑连贯,适合需要避免中间变量的场景。

方案三:简化索引匹配逻辑

如果偏好基于索引元组匹配,可通过index.to_frame将索引转为DataFrame后生成元组,再进行筛选:

mean_col0 = df.groupby(['idx0', 'idx1'])['col0'].mean()
level_idxs = mean_col0.groupby('idx0').idxmin()

# 将前两级索引转为元组,再匹配level_idxs
result = df[df.index.to_frame()[['idx0', 'idx1']].apply(tuple, axis=1).isin(level_idxs)]

优势:比原方案的droplevel更直观,明确展示是基于前两级索引进行匹配。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 07:36:19