pandas - 按两个函数分组

3

我一直在尝试对pandas groupby对象进行累加求和操作。我需要使用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进行调整,但似乎无法解决。任何帮助将不胜感激。

2个回答

3

使用 lambda函数 结合 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
你的第一个操作 df.groupby('A').cumsum() 的结果是一个常规数据框。它等同于 df.groupby('A')[['B']].cumsum(),但 Pandas 方便地允许你省略索引部分 [['B']]
因此,对该数据框的任何后续操作默认情况下都不会按组执行,除非你再次使用 GroupBy
res = df.groupby('A').cumsum().groupby(df['A']).shift()

但是,正如您所看到的,这会重复分组操作并且效率低下。相反,您可以定义一个单一的函数,将cumsumshift按正确顺序组合起来,然后将此函数应用于单个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

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