以大Pandas为单位的累积总和,以零开始,以除最后一组外的所有项目总和结束

2024-06-01 13:50:28 发布

您现在位置:Python中文网/ 问答频道 /正文

在下面的数据框中,我想创建一个新列C,它将是A列中每个组的B累积和,但是这些和必须从零开始,并且只在该组的倒数第二个条目之前添加值

  A B
0 1 5
1 1 6
2 2 3
3 2 4
4 2 5
5 3 2
5 3 7
6 4 3

因此,我的结果应该是:

  A B C
0 1 5 0
1 1 6 5
2 2 3 0
3 2 4 3
4 2 5 7
5 3 2 0
5 3 7 2
6 4 3 0

(我认为这个问题很明显,但不知何故,我自己也弄不明白,也看不到任何地方已经问过了。)


Tags: 数据地方条目倒数
3条回答

另一种选择是使用^{}两次,如下所示:

A下取B^{}值,这样对于每组A,将重置B的第一个条目,并在以后的^{}0期间变为NaN

A的局部序列中,进一步按A分组^{},以获得所需的输出:

df['C'] = (df.groupby('A')['B'].shift()
             .groupby(df['A']).cumsum()
             .fillna(0, downcast='infer')
          )

此解决方案是矢量化的,并且支持非连续组

结果:

print(df)


   A  B  C
0  1  5  0
1  1  6  5
2  2  3  0
3  2  4  3
4  2  5  7
5  3  2  0
5  3  7  2
6  4  3  0

编辑

如果您要按多个列分组,并且得到“KeyError”,请检查您的语法输入是否正确,例如:

如果按2列yearincome分组,则可以使用:

df['C'] = (df.groupby(['year', 'income'])['B'].shift()
             .groupby([df['year'], df['income']]).cumsum()
             .fillna(0, downcast='infer')
          )

Pandas支持使用或不使用df将参数传递给.groupby()的语法。但是,对于被分组的实体本身不是df的任何groupby(),我们可能无法使用缩写形式仅引用列标签,例如'year',我们需要使用完整的列名,例如df['year']

尝试:

df["C"] = df.groupby("A")["B"].transform(
    lambda x: x.shift().fillna(0).cumsum().astype(int)
)
print(df)

印刷品:

   A  B  C
0  1  5  0
1  1  6  5
2  2  3  0
3  2  4  3
4  2  5  7
5  3  2  0
5  3  7  2
6  4  3  0

如果您的组已经是连续的,您可以shift并使用whereNaN跨组的行。移位还确保累计和与前几行相关,并且统计值为0,这是您想要的。然后使用内置的groupby+cumsum来避免较慢的lambda

s = df['A'].shift()

df['C'] = (df.shift()
             .where(df['A'].eq(s))
             .groupby('A')['B'].cumsum()
             .fillna(0, downcast='infer'))


#   A  B  C
#0  1  5  0
#1  1  6  5
#2  2  3  0
#3  2  4  3
#4  2  5  7
#5  3  2  0
#5  3  7  2
#6  4  3  0

如果分组行不是连续的,我们也可以处理这个问题。唯一的小修改是,我们需要基于分组列进行稳定排序(这样组内的顺序被保留,并且cumsum是正确的),然后最后我们可以对索引进行排序,以返回到数据帧的原始顺序,如果这很重要的话

# Create DataFrame with non-consecutive groups, 
df = pd.concat([df[::2], df[1::2]], ignore_index=True)
#   A  B
#0  1  5
#1  2  3
#2  2  5
#3  3  7
#4  1  6
#5  2  4
#6  3  2
#7  4  3

df = df.sort_values('A', kind='mergesort')

s = df['A'].shift()

df['C'] = (df.shift()
             .where(df['A'].eq(s))
             .groupby('A')['B'].cumsum()
             .fillna(0, downcast='infer'))

df = df.sort_index()
#   A  B  C
#0  1  5  0
#1  2  3  0
#2  2  5  3  <- Previous row `1` has value 3
#3  3  7  0
#4  1  6  5  <- Previous row `0` has value 5
#5  2  4  8  <- Previous rows `1` and `2` has values 3 + 5 = 8
#6  3  2  7  <- Previous row `3` has value 7 
#7  4  3  0

相关问题 更多 >