多重索引数据框中列之间的数学运算

5

我有一个带有多级索引的数据框,我需要对它进行切片并在切片之间执行数学运算。

# sample df
idx=pd.IndexSlice
np.random.seed(123)
tuples = list(zip(*[['one', 'one', 'two', 'two', 'three', 'three'],['foo', 'bar', 'foo', 'bar', 'foo', 'bar']]))
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
df = pd.DataFrame(np.random.randn(3, 6), index=['A', 'B', 'C'], columns=index)

如果我想在各列之间进行加减运算,我可以使用索引切片来执行,例如:

df.loc[:,idx['three','foo']] - df.loc[:,idx['two','foo']]

然而,如果我想使用更高级别的切片,它将无法工作并返回NaN:

# not working
df.loc[:,idx['three',:]] - df.loc[:,idx['two',:]]

有没有一种简单的方法可以使用数据框的更高级别的切片,仅添加/减去相应的列?我的数据框可能包含多级索引中的数百列。谢谢。

3个回答

6
如果需要在输出中使用 MultiIndex,请使用 `rename` 来处理相同级别的 MultiIndex:
df = df.loc[:,idx['three',:]] - df.loc[:,idx['two',:]].rename(columns={'two':'three'})
print (df)
first      three          
second       foo       bar
A      -0.861579  3.157731
B      -1.944822  0.772031
C       2.649912  2.621137

优点是可以将两个级别重命名为新的索引名称,并加入到原始数据中:
df = (df.join(df.loc[:,idx['three',:]].rename(columns={'three':'four'}) - 
              df.loc[:,idx['two',:]].rename(columns={'two':'four'})))
print (df)
first        one                 two               three                four  \
second       foo       bar       foo       bar       foo       bar       foo   
A      -1.085631  0.997345  0.282978 -1.506295 -0.578600  1.651437 -0.861579   
B      -2.426679 -0.428913  1.265936 -0.866740 -0.678886 -0.094709 -1.944822   
C       1.491390 -0.638902 -0.443982 -0.434351  2.205930  2.186786  2.649912   

first             
second       bar  
A       3.157731  
B       0.772031  
C       2.621137  

如果不必要,请使用 DataFrame.xs
df1 = df.xs('three', axis=1, level=0) - df.xs('two', axis=1, level=0)
print (df1)
second       foo       bar
A      -0.861579  3.157731
B      -1.944822  0.772031
C       2.649912  2.621137

如果需要第一层索引的可能解决方案之一是 MultiIndex.from_product
df1 = df.xs('three', axis=1, level=0) - df.xs('two', axis=1, level=0)
df1.columns = pd.MultiIndex.from_product([['new'], df1.columns], 
                                         names=['first','second'])
print (df1)
first        new          
second       foo       bar
A      -0.861579  3.157731
B      -1.944822  0.772031
C       2.649912  2.621137

谢谢,重命名选项非常好用。还有一个问题 - 如果我想同时重命名输出中的下一级,最好的方法是什么?比如说 four/ bar_delta, foo_delta? - whada
@whada - 使用 df = df.rename(columns={'foo':'bar'}, level=1),但需要重命名所有值,因为会出现相同的问题,导致 NaN。 - jezrael

1
你可以尝试使用DataFrame.xs(横截面):
df.xs(('three'), axis=1) - df.xs(('two'), axis=1)

1
在这种情况下,最简单的方法可能是:
df.loc[:, 'two'] - df.loc[:, 'three']

几乎关于MultiIndex的所有内容都可以在@coldspeed的canonicals中找到。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接