如何聚合MultiIndexed Pandas DataFrame指定行子集并追加汇总行?
问题设置与目标
我有一个如下所示的MultiIndexed Pandas DataFrame:
import pandas as pd df = pd.DataFrame({ 'Values':[1, 3, 4, 8, 5, 2, 9, 0, 2], 'A':['A1', 'A1', 'A1', 'A1', 'A2', 'A2', 'A3', 'A3', 'A3'], 'B':['foo', 'bar', 'fab', 'baz', 'foo', 'baz', 'qux', 'baz', 'bar'] }) df.set_index(['A','B'], inplace=True) print(df.to_string())
输出结果:
Values A B A1 foo 1 bar 3 fab 4 baz 8 A2 foo 5 baz 2 A3 qux 9 baz 0 bar 2
我的最终目标是用最简单、最标准的Pandas方法,将B列中所有"bar"和"baz"行替换为名为"other"的求和行(如下所示):
Values A B A1 foo 1 fab 4 other 11 A2 foo 5 other 2 A3 qux 9 other 2
当前进展
我已经学会了为MultiIndex DataFrame创建掩码,标记需要聚合的行(这些行在agg_list中):
agg_list = ['bar', 'baz'] # 创建掩码,标记B列中属于agg_list的行 filterFunc = lambda x: x.index.get_level_values('B') in agg_list mask = df.groupby(level=['A','B']).apply(filterFunc)
生成的掩码如下:
A B A1 bar True baz True fab False foo False A2 baz True foo False A3 bar True baz True qux False
我也知道如何移除不需要的行:
# 使用掩码移除B列中属于agg_list的行 df_masked = df[[~mask.loc[i1, i2] for i1,i2 in df.index]] print(df_masked.to_string())
输出结果:
Values A B A1 foo 1 fab 4 A2 foo 5 A3 qux 9
但我不知道如何对这些被标记的行进行聚合求和,并将结果作为"other"行追加到每个A分组中。
类似问题与解决方案
我见过思路类似的非MultiIndex场景解决方案,但无法直接套用:
threshold = 6 m = df['value'] < threshold df1 = df[~m].copy() df1.loc['Z'] = df.loc[m, 'value'].sum()
或者:
m = df['value'] < threshold df1 = df[~m].append(df.loc[m, ['value']].sum().rename('Z'))
解决方案
这里提供两种简洁的标准实现方式:
方法一:分组聚合后合并
先提取并保留不需要聚合的行,再对目标行按A分组求和并设置新索引,最后合并排序:
agg_list = ['bar', 'baz'] # 提取需要保留的行(B值不在agg_list中) df_keep = df[~df.index.get_level_values('B').isin(agg_list)] # 对目标行按A分组求和,将B列设置为"other"并追加索引 df_other = df[df.index.get_level_values('B').isin(agg_list)] \ .groupby(level='A').sum() \ .assign(B='other') \ .set_index('B', append=True) # 合并两个数据集并按索引排序 result = pd.concat([df_keep, df_other]).sort_index() print(result.to_string())
方法二:替换后分组求和
先将B列中的目标值替换为"other",再按A和B分组求和,一步到位:
agg_list = ['bar', 'baz'] # 重置索引后替换B列的目标值 df_copy = df.reset_index() df_copy['B'] = df_copy['B'].replace(agg_list, 'other') # 按A和B分组求和,重新设置多级索引 result = df_copy.groupby(['A', 'B']).sum().sort_index() print(result.to_string())
两种方法都能得到预期结果,其中方法二更简洁,适合这类替换后聚合的场景。
内容的提问来源于stack exchange,提问作者water_with_camphor
相关产品推荐
相关产品推荐

