考虑以下
DataFrame
:
df = pd.DataFrame({'c0':['1980']*3+['1990']*2+['2000']*3,
'c1':['x','y','z']+['x','y']+['x','y','z'],
'c2':range(8) })
c0 c1 c2
0 1980 x 0
1 1980 y 1
2 1980 z 2
3 1990 x 3
4 1990 y 4
5 2000 x 5
6 2000 y 6
7 2000 z 7
我想用
pandas
的groupby
在c0
上做以下事情:
c0
(indicate year).c2
的值中减去y
的c1
(在c2
中)的值。c3
收集这些值。最后的结果是
c0 c1 c2 c3
0 1980 x 0 -1
1 1980 y 1 0
2 1980 z 2 1
3 1990 x 3 -1
4 1990 y 4 0
5 2000 x 5 -1
6 2000 y 6 0
7 2000 z 7 1
我能够在没有
groupby
的情况下得到如下结果:
dic = {}
for yr in df['c0'].unique():
cond1 = ( df['c0']==yr )
tmp = df.loc[cond1,:].copy()
cond2 = ( tmp['c1']=='y' )
val = tmp.loc[cond2,'c2'].to_numpy()
tmp['c3'] = tmp['c2'] - val
dic[yr] = tmp
pd.concat([dic['1980'],dic['1990'],dic['2000']])
它有效但看起来不太好。我尝试了
transform
和 apply
的 groupby
,但无法弄清楚。任何帮助将不胜感激。
在使用
y
隐藏组的所有非 y 行后,您可以使用 transform
广播 where
值:
df['c3' ] = df['c2'] - df.where(df['c1'] == 'y').groupby(df['c0'])['c2'].transform('max')
print(df)
# Output
c0 c1 c2 c3
0 1980 x 0 -1.0
1 1980 y 1 0.0
2 1980 z 2 1.0
3 1990 x 3 -1.0
4 1990 y 4 0.0
5 2000 x 5 -1.0
6 2000 y 6 0.0
7 2000 z 7 1.0
这是多索引选择的新功能
s = df.set_index(['c0', 'c1'])
s['c3'] = s['c2'] - s['c2'].xs('y', level=1)
s = s.reset_index()
结果
c0 c1 c2 c3
0 1980 x 0 -1
1 1980 y 1 0
2 1980 z 2 1
3 1990 x 3 -1
4 1990 y 4 0
5 2000 x 5 -1
6 2000 y 6 0
7 2000 z 7 1
另一种可能的解决方案:
df['c3'] = (df.groupby('c0')
.apply(lambda g: g['c2'].values-g.loc[g['c1'].eq('y'), 'c2'].values)
.explode().values)
输出:
c0 c1 c2 c3
0 1980 x 0 -1
1 1980 y 1 0
2 1980 z 2 1
3 1990 x 3 -1
4 1990 y 4 0
5 2000 x 5 -1
6 2000 y 6 0
7 2000 z 7 1