问题设置和目标
我有一个多索引的 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
目前的工作
我设法从 a similar problem 弄清楚如何为 MultiIndex DataFrame 创建掩码突出显示我们最终要聚合的行,这些行位于 agg_list 中。
agg_list = ['bar', 'baz']
# Create a mask that highlights the rows in B that are in agg_list
filterFunc = lambda x: x.index.get_level_values('B') in agg_list
mask = df.groupby(level=['A','B']).apply(filterFunc)
这会产生预期的掩码:
print(mask.to_string())
A B
A1 bar True
baz True
fab False
foo False
A2 baz True
foo False
A3 bar True
baz True
qux False
而且我知道如何删除不再需要的行:
# Remove rows in B col that are in agg_list using mask
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
但我不知道如何对这些行进行实际的聚合/求和并将其附加到每个多索引行。
类似问题/解决方案
我见过的类似问题不涉及 Multiindex DataFrame,因此我不能完全使用某些解决方案,例如 this one ,它具有创建掩码然后附加汇总行的相同总体思路:
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'))
最佳答案
这是一种为 B
重置索引、执行替换并聚合值的方法。
agg_list = ['bar', 'baz']
(df.reset_index(level=1)
.replace({'B':{'|'.join(agg_list):'other'}},regex=True)
.groupby(['A','B']).sum())
另一种方法是创建一个新的 MultiIndex,将 bar
和 baz
替换为 other
。
(df.set_axis(pd.MultiIndex.from_arrays([df.index.get_level_values(0),
df.index.get_level_values(1).str.replace('|'.join(agg_list),'other')]))
.groupby(level=[0,1]).sum())
输出:
Values
A B
A1 fab 4
foo 1
other 11
A2 foo 5
other 2
A3 other 2
qux 9
关于python - 如何聚合行的子集并附加到 MultiIndexed Pandas DataFrame?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73228173/