pandas Groupby总和与累计总和-返回 Dataframe 与系列

smdncfj3  于 2023-01-04  发布在  其他
关注(0)|答案(1)|浏览(176)

我注意到,当我们groupby一个dataframe & sum时,我们得到一个完整的dataframe作为回报:

dict1 = {'A': {0: 'A0', 1: 'A0', 2: 'A0', 3: 'A0', 4: 'A1', 5: 'A1', 6: 'A1', 7: 'A1', 8: 'A1', 9: 'A1'}, 'B': {0: 'B0', 1: 'B1', 2: 'B2', 3: 'B3', 4: 'B4', 5: 'B5', 6: 'B6', 7: 'B7', 8: 'B8', 9: 'B9'}, 'C': {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}, 'D': {0: 10, 1: 11, 2: 12, 3: 13, 4: 14, 5: 15, 6: 16, 7: 17, 8: 18, 9: 19}, 'E': {0: 'E0', 1: 'E1', 2: 'E0', 3: 'E1', 4: 'E0', 5: 'E1', 6: 'E0', 7: 'E1', 8: 'E0', 9: 'E1'}}

df2 = pd.DataFrame(dict1)
A   E 
A0  E0    22
    E1    24
A1  E0    48
    E1    51
Name: D, dtype: int64

但是当我执行cumsum时,它只返回结果累积序列。为什么它们的行为不同?我如何使cumsum与分组的dataframe一起返回,而不将其赋值回去?
一个二个一个一个

    • 编辑:**我原以为这是一个简单的解决方法,我可以处理剩下的问题。但根据你目前的评论,这让我偏离了我的最终目标。我希望最终实现一组多个变量的总和、平均值、累计值--如下所示:
df2.groupby(['A','E']).agg({'D':'cumsum','C':lambda x: 4*np.sum(x)})

但它会给出如下输出:

D   C
0   10.0    NaN
1   11.0    NaN
2   22.0    NaN
3   24.0    NaN
4   14.0    NaN
5   15.0    NaN
6   30.0    NaN
7   32.0    NaN
8   48.0    NaN
9   51.0    NaN
(A0, E0)    NaN 8.0
(A0, E1)    NaN 16.0
(A1, E0)    NaN 72.0
(A1, E1)    NaN 84.0

那么,有没有一种方法可以在不单独处理累积和的情况下实现呢?

a64a0gku

a64a0gku1#

基于你在两个脚本中已经看到的行为,很容易理解这一点。pd.Series.cumsum()为每个组返回与列D相同长度的另一个序列,而你的lambda函数为每个组返回一个值,这导致返回的索引不同。
您所要做的就是使用另一个lambda函数来捕获每个组级别上的完整cumsum操作,这个lambda函数返回一个列表对象作为聚合,而不是一个系列输出作为转换。

t = {
    'D': lambda x: list(x.cumsum()),
    'C': lambda x: 4*np.sum(x)
    }

result = df2.groupby(['A','E']).agg(t)
result
D   C
A  E                   
A0 E0      [10, 22]   8
   E1      [11, 24]  16
A1 E0  [14, 30, 48]  72
   E1  [15, 32, 51]  84

这将返回由A列和E列组成的组级别的 Dataframe 。
但是,如果您希望 Dataframe 具有与原始 Dataframe 相同的索引,则只需explode新列D即可
一个二个一个一个

    • 编辑1:基于我的评论的其他信息**
  • 简单地说,sum是一个聚合,为每个组返回一个值(float/int),而cumsum是一个转换,返回一个与输入行数相同的序列。
  • cumsum基本上转换给定的输入序列(每组D列的行)并返回另一个序列。
  • sum返回带有索引的序列作为答案中的第一个脚本,cumsum返回索引作为答案中的第二个脚本。当Pandas试图协调它们时,它会堆叠索引,因为它们不匹配。
  • 例如,对于组(A1,E0)-〉cumsum,返回具有3个值[14,30,48]的序列,而sum返回值72的聚合
    • 编辑2:根据您的注解在groupby上使用transform进行编码**

如果你想避免使用lambda函数,正如我从你的评论中所理解的,你可以在groupby对象上使用transform方法,但是这不允许同时为不同的列传递多个转换作为一个dict,所以你仍然需要重新分配这些列。

grouper = df2.groupby(['A','E'])                #<- create grouper

df2['C_new'] = grouper['C'].transform('sum')    #<- use your lambda function here if you need
df2['D_new'] = grouper['D'].transform('cumsum') #<- transformation here
print(df2)
A   B  C   D   E  C_new  D_new
0  A0  B0  0  10  E0      2     10
1  A0  B1  1  11  E1      4     11
2  A0  B2  2  12  E0      2     22
3  A0  B3  3  13  E1      4     24
4  A1  B4  4  14  E0     18     14
5  A1  B5  5  15  E1     21     15
6  A1  B6  6  16  E0     18     30
7  A1  B7  7  17  E1     21     32
8  A1  B8  8  18  E0     18     48
9  A1  B9  9  19  E1     21     51

相关问题