给定一个多索引 Pandas 数据框 df2,我想计算每个类别中每一行与上面行的差异。
import pandas as pd
inner = ('a','b','c')
cols = ('A','B','C','D')
df1=pd.DataFrame(np.random.randn(3,4), index=inner, columns=cols)
df2=pd.concat([df1,df1],keys=['X','Y'])
Run Code Online (Sandbox Code Playgroud)
df2:
A B C D
X a -0.391804 -0.307916 -0.265643 -0.222193
b -0.142498 -1.389972 1.060328 1.207945
c 1.156881 1.596382 0.620923 0.592739
Y a -0.391804 -0.307916 -0.265643 -0.222193
b -0.142498 -1.389972 1.060328 1.207945
c 1.156881 1.596382 0.620923 0.592739
Run Code Online (Sandbox Code Playgroud)
这是我尝试过的:
df2.groupby(level=[0]).apply(lambda x: df2.loc[x.index[:-1]-df2.loc[x.index[1:]]])
Run Code Online (Sandbox Code Playgroud)
但这会得到一个带有三级索引的错误结果数据框。
A B C D
X X a -0.391804 -0.307916 -0.265643 -0.222193
b -0.142498 -1.389972 1.060328 1.207945
Y Y a -0.391804 -0.307916 -0.265643 -0.222193
b -0.142498 -1.389972 1.060328 1.207945
Run Code Online (Sandbox Code Playgroud)
您不能按索引 b/c 的所有级别进行分组,那么每个组将只有 1 行,并且没有什么可减去的。另外,使用非随机数据(减法不直观)让我们稍微改变一下你的例子:
import pandas
import numpy as np
df = pandas.DataFrame(
data={'A': np.arange(8) ** 2, 'B': np.arange(8) ** 0.5},
index=pandas.MultiIndex.from_product([list('XY'), list('abcd')])
)
df
# A B
# X a 0 0.000000
# b 1 1.000000
# c 4 1.414214
# d 9 1.732051
# Y a 16 2.000000
# b 25 2.236068
# c 36 2.449490
# d 49 2.645751
Run Code Online (Sandbox Code Playgroud)
所以如果我们只沿着索引级别的一个子集分组,我们可以使用shift数据框的方法来获得每个组内的滚动差异:
df.groupby(level=[0]).transform(lambda g: g.shift(-1) - g)
# A B
# X a 1 1.000000
# b 3 0.414214
# c 5 0.317837
# d NaN NaN
# Y a 9 0.236068
# b 11 0.213422
# c 13 0.196262
# d NaN NaN
Run Code Online (Sandbox Code Playgroud)