我一直试图在熊猫groupby对象上获得一个积木。我需要将cumsum移位一位,这是通过shift()实现的。但是,在单个groupby对象上同时执行这两项功能会产生一些不良结果:
df = pd.DataFrame({'A': [1, 1, 1, 2, 2, 2],
'B': [2, 3, 5, 2, 3, 5]})
df.groupby('A').cumsum().shift()
给出:
B
0 NaN
1 2.0
2 5.0
3 10.0
4 2.0
5 5.0
即组1上的cumsum()的最后一个值移到组2的第一个值。我要这些组保持分隔,并得到:
B
0 NaN
1 2.0
2 5.0
3 NaN
4 2.0
5 5.0
但是我不确定如何使这两个函数在groupby对象上组合工作。在其他任何地方都找不到此问题。一直在玩agg,但似乎无法解决。任何帮助将不胜感激。
答案 0 :(得分:3)
将lambda function
与GroupBy.apply
一起使用,也有必要在groupby
之后定义列表中的列以进行处理:
df['B'] = df.groupby('A')['B'].apply(lambda x: x.cumsum().shift())
print (df)
A B
0 1 NaN
1 1 2.0
2 1 5.0
3 2 NaN
4 2 2.0
5 2 5.0
答案 1 :(得分:1)
first 操作df.groupby('A').cumsum()
的结果是常规数据帧。它等效于df.groupby('A')[['B']].cumsum()
,但是Pandas方便地省略了[['B']]
索引部分。
因此,默认情况下,将不会 对该数据帧进行任何后续操作,除非您再次使用GroupBy
:
res = df.groupby('A').cumsum().groupby(df['A']).shift()
但是,正如您所看到的,这将重复分组操作,并且效率很低。您可以定义一个单个函数,该函数以正确的顺序组合cumsum
和shift
,然后将此函数应用于单个GroupBy
对象。定义单个函数称为function composition,它不是Python固有的。这里有一些替代方法:
这是一个明确的建议解决方案:
def cum_shift(x):
return x.cumsum().shift()
res1 = df.groupby('A')[['B']].apply(cum_shift)
lambda
函数上述内容的单行版本:
res2 = df.groupby('A')[['B']].apply(lambda x: x.cumsum().shift())
这是一个纯粹的功能解决方案;例如,通过第三方toolz
:
from toolz import compose
from operator import methodcaller
cumsum_shift_comp = compose(methodcaller('shift'), methodcaller('cumsum'))
res3 = df.groupby('A')[['B']].apply(cumsum_shift_comp)
以上所有均给出相同的结果:
assert res.equals(res1) and res1.equals(res2) and res2.equals(res3)
print(res1)
B
0 NaN
1 2.0
2 5.0
3 NaN
4 2.0
5 5.0