Pandas:组内有两个条件的累计和

Pandas: Cumulative sum within group with two conditions

我有一个如下所示的 DataFrame table:

索引 x y value_1 cumsum_1 cumsum_2
0 0.1 1 12 12 0
1 1.2 1 10 12 10
2 0.25 1 7 19 10
3 1.0 2 3 0 3
4 0.72 2 5 5 10
5 1.5 2 10 5 13

所以我的目标是计算value_1的累计和。但有两个条件必须考虑。

有人知道吗?

可以在x < 1或x >= 1条件下使用.where()根据条件临时修改value_1的值为0,然后groupby cumsum,如下:

第二个条件由 .groupby 函数满足,而第一个条件由 .where() 函数满足,详情如下:

.where() 在条件为真时保留列值,在条件为假时更改值(在本例中为 0)。因此,对于列 x < 1 的第一个条件,value_1 将保留其值以提供给后续 cumsum 步骤以累积 value_1 的过滤值。对于条件 x < 1 为 False 的行,value_1 将其值屏蔽为 0。这些 0 传递给 cumsum 进行累加实际上与取出原始值的效果相同value_1为累积成 列 cumsum_1.

第二行代码将value_1个值累加到cumsum_2列,条件相反x >= 1。这两行代码实际上分配了value_1cumsum_1cumsum_2 分别根据 x < 1 和 x >= 1。

(感谢@tdy 精简代码的建议)

df['cumsum_1'] = df['value_1'].where(df['x'] < 1, 0).groupby(df['y']).cumsum()
df['cumsum_2'] = df['value_1'].where(df['x'] >= 1, 0).groupby(df['y']).cumsum()

结果:

print(df)

      x  y  value_1  cumsum_1  cumsum_2
0  0.10  1       12        12         0
1  1.20  1       10        12        10
2  0.25  1        7        19        10
3  1.00  2        3         0         3
4  0.72  2        5         5         3
5  1.50  2       10         5        13

这是另一种使用枢轴的方法:

(df.assign(ge1=df['x'].ge(1).map({True: 'cumsum_2', False: 'cumsum_1'}))
   .pivot(columns='ge1', values='value_1').fillna(0).groupby(df['y']).cumsum()
   .astype(int)
)

输出:

ge1  cumsum_1  cumsum_2
0          12         0
1          12        10
2          19        10
3           0         3
4           5         3
5           5        13

完整代码:

df[['cumsum_1', 'cumsum_2']] = (df.assign(ge1=df['x'].ge(1).map({True: 'cumsum_2', False: 'cumsum_1'}))
                                  .pivot(columns='ge1', values='value_1').fillna(0).groupby(df['y']).cumsum()
                                  .astype(int)
                                )

(或用pd.concat拼接)

输出:

   index     x  y  value_1  cumsum_1  cumsum_2
0      0  0.10  1       12        12         0
1      1  1.20  1       10        12        10
2      2  0.25  1        7        19        10
3      3  1.00  2        3         0         3
4      4  0.72  2        5         5         3
5      5  1.50  2       10         5        13

与上述方法类似,但链接更多。

df[['cumsum_1a', 'cumsum2a']] = (df.
 assign(
    v1 = lambda temp: temp.x >= 1,
    v2 = lambda temp: temp.v1 * temp.value_1,
    v3 = lambda temp: ~ temp.v1 * temp.value_1
    ).
 groupby('y')[['v2', 'v3']].
 cumsum()
 )