Python 使用groupby变换从特定行中减去值
具有包含多个组的数据帧(列Python 使用groupby变换从特定行中减去值,python,pandas,group-by,transform,Python,Pandas,Group By,Transform,具有包含多个组的数据帧(列Id)。在每个组中有几个级别(列级别)。所有组都有一个名为'Base'的级别。对于每个组,我想从所有其他级别的值中减去'Base'值 使用pandas.join,来回一点,我就能得到我想要的东西 import pandas as pd df = pd.DataFrame({'Id':['A', 'A', 'A', 'B', 'B', 'B'], 'Level':['Down', 'Base', 'Up', 'Base', 'Dow
Id
)。在每个组中有几个级别(列级别
)。所有组都有一个名为'Base'
的级别。对于每个组,我想从所有其他级别的值中减去'Base'
值
使用pandas.join
,来回一点,我就能得到我想要的东西
import pandas as pd
df = pd.DataFrame({'Id':['A', 'A', 'A', 'B', 'B', 'B'],
'Level':['Down', 'Base', 'Up', 'Base', 'Down', 'Up'],
'Value':[8, 10, 15, 6, 3, 8]
}).set_index('Id')
df = df.join(df[df['Level']=='Base']['Value'], rsuffix='_Base')
df['Delta'] = df['Value'] - df['Value_Base']
df.drop('Value_Base', inplace=True, axis=1)
#The input
df_in
Out[3]:
Level Value
Id
A Down 8
A Base 10
A Up 15
B Base 6
B Down 3
B Up 8
# The output after the above operation (and hopefully after a groupby.transform)
df_out
Out[4]:
Level Value Delta
Id
A Down 8 -2
A Base 10 0
A Up 15 5
B Base 6 0
B Down 3 -3
B Up 8 2
我想上面的解决方案还不错,但我希望使用groupby
和transform
也能达到同样的效果。我试过了
df_in.groupby('Id').transform(lambda x : x['Value'] - x[x['Level']=='Base']['Value'])
但这并不奏效。有人能告诉我我做错了什么吗?没有变换,但我认为这很酷:
df['Delta']=df['Value']-df.pivot(columns='Level')['Value']['Base']
Level Value Delta
Id
A Down 8 -2
A Base 10 0
A Up 15 5
B Base 6 0
B Down 3 -3
B Up 8 2
如果真的需要
transform
并且总是Base
每个组,一个可能的解决方案是创建MultiIndex
,然后通过xs
选择:
df['Delta'] =df['Value'] - (df.set_index('Level', append=True)
.groupby(level=0)['Value']
.transform(lambda x: x.xs('Base', level=1)[0])
.values)
print (df)
Level Value Delta
Id
A Down 8 -2
A Base 10 0
A Up 15 5
B Base 6 0
B Down 3 -3
B Up 8 2
如果组中不存在一些Base
,类似的解决方案也有效:
f = lambda x: next(iter(x.xs('Base', level=1)), np.nan)
df = df.set_index('Level', append=True)
df['Delta'] = df['Value'] - df.groupby(level=0)['Value'].transform(f)
df = df.reset_index(level=1)
print (df)
Level Value Delta
Id
A Down 8 -2
A Base 10 0
A Up 15 5
B Base 6 0
B Down 3 -3
B Up 8 2
更好的解决方案是:
df['Delta'] = df['Value'] - df.index.map(df.loc[df['Level'].eq('Base'), 'Value'])
print (df)
Level Value Delta
Id
A Down 8 -2
A Base 10 0
A Up 15 5
B Base 6 0
B Down 3 -3
B Up 8 2
这就是我目前正在做的事情。问题是如何使用
groupby.transform
.Nice实现同样的效果。无论是否转换,您都可以通过一行易读的代码实现想要的结果+太好了。根据您和Billy Bonnaros的回答,这里的转换
函数似乎不是最佳选择。