Pandas条件滚动求和两列

4

我有一个数据框中的四列数据,如下所示:

       A   B     C        D
75472  d1  x    -36.0   0.0
75555  d2  x    -38.0   0.0
75638  d3  x    -18.0   0.0
75721  d4  x    -18.0   1836.0
75804  d5  x    1151.0  0.0
75887  d6  x    734.0   0.0
75970  d7  x    -723.0  0.0

我想要根据以下条件对D进行条件求和:

  • 如果D有值,则使用D的值
  • 否则,将前一行的D值加上C的值作为D的值

因此,在上述情况下,D应为[-36,-74,-92,1836,2987,3721,2998]

我已成功使用for循环实现此操作。

for i, row in me.iterrows():
    try:
        if row['D'] > 0:
            step1 = me.loc[(me['B'] == row['B']) & (me['A'] == row['A']), 'output'].iloc[0]
            me_copy.iloc[i, me_copy.columns.get_loc('output')] = step1
        else:
            step1 = me.loc[(me['B'] == row['B']) & (me['A'] == (row['A'] - pd.DateOffset(days=1))), 'step1'].iloc[0]
            receipts_adjustments_sales = me.loc[(me['B'] == row['B']) & (me['A'] == row['A']), 'C'].iloc[0]
            me_copy.iloc[i, me_copy.columns.get_loc('output')] = step1 + receipts_adjustments_sales
    except:
        me_copy.iloc[i, me_copy.columns.get_loc('output')] = 0

但是for循环明显非常耗费资源,是一种反模式,并且基本上无法运行整个数据框。我试图复制一个在数据面板上编写的excel函数,但我始终无法弄清如何使用以下方法:

  • pd.Series.shift()
  • pd.Series.rolling()
  • 仅计算不同列的值

我曾经尝试使用shift()来实现,但我意识到我不得不为每一行创建一个单独的列,这就是我选择使用for循环的原因。

通用于分组

df.loc[:, 'A_group'] = df.groupby(['A'])[df['D'] != 0].cumsum()
df.loc[:, 'E'] = df['D'].mask(df['D'] == 0).combine_first(df['C'])
df.loc[:, 'F'] = me.groupby(['A', 'A_group'])['E'].cumsum()

感谢Scott Boston提供的帮助!

2个回答

5

这里提供一种方法:

grp = (df['D'] != 0).cumsum()
df['D_new'] = df['D'].mask(df['D'] == 0).combine_first(df['C']).groupby(grp).cumsum()
df

输出:

        A  B       C       D   D_new
75472  d1  x   -36.0     0.0   -36.0
75555  d2  x   -38.0     0.0   -74.0
75638  d3  x   -18.0     0.0   -92.0
75721  d4  x   -18.0  1836.0  1836.0
75804  d5  x  1151.0     0.0  2987.0
75887  d6  x   734.0     0.0  3721.0
75970  d7  x  -723.0     0.0  2998.0

细节:

创建grps以帮助cumsum。每个组都由“D”中某个值的出现定义,因此在该值之前停止cumsum,并选择D的该值,然后继续cumsum直到“D”的下一个值。

grp = (df['D'] != 0).cumsum()

输出:

        A  B       C       D   D_new  grp
75472  d1  x   -36.0     0.0   -36.0    0
75555  d2  x   -38.0     0.0   -74.0    0
75638  d3  x   -18.0     0.0   -92.0    0
75721  d4  x   -18.0  1836.0  1836.0    1
75804  d5  x  1151.0     0.0  2987.0    1
75887  d6  x   734.0     0.0  3721.0    1
75970  d7  x  -723.0     0.0  2998.0    1

现在,当D中有非零数字时,让我们创建一个新的列,将'C'和'D'组合在一起。
df['newCD'] = df['D'].mask(df['D'] == 0).combine_first(df['C'])

输出:

        A  B       C       D   D_new  grp   newCD
75472  d1  x   -36.0     0.0   -36.0    0   -36.0
75555  d2  x   -38.0     0.0   -74.0    0   -38.0
75638  d3  x   -18.0     0.0   -92.0    0   -18.0
75721  d4  x   -18.0  1836.0  1836.0    1  1836.0
75804  d5  x  1151.0     0.0  2987.0    1  1151.0
75887  d6  x   734.0     0.0  3721.0    1   734.0
75970  d7  x  -723.0     0.0  2998.0    1  -723.0

最后,按照 'grp' 分组并对新的 CD 列进行 cumsum

df['D_new_Details'] = df.groupby('grp')['newCD'].cumsum()

输出:

        A  B       C       D   D_new  grp   newCD  D_new_Details
75472  d1  x   -36.0     0.0   -36.0    0   -36.0          -36.0
75555  d2  x   -38.0     0.0   -74.0    0   -38.0          -74.0
75638  d3  x   -18.0     0.0   -92.0    0   -18.0          -92.0
75721  d4  x   -18.0  1836.0  1836.0    1  1836.0         1836.0
75804  d5  x  1151.0     0.0  2987.0    1  1151.0         2987.0
75887  d6  x   734.0     0.0  3721.0    1   734.0         3721.0
75970  d7  x  -723.0     0.0  2998.0    1  -723.0         2998.0

这个有效,谢谢!有没有办法将其推广到A、B组?此外 - 有没有关于此的好文档?即使阅读了文档,Pandas中的某些一行代码对我来说就像魔法一样。 - gr1zzly be4r
不能将它归纳为A、B组的一部分吗?你的解释非常有帮助,谢谢! - gr1zzly be4r
@gr1zzlybe4r 哦.. 我相信我们可以将A和B添加到分组中。我只是在说明目前没有关于这个特定算法的文档。至少我不知道有任何文档。你只需要修改grp语句以使用A和B创建你想要的组。 - Scott Boston
1
嗯,要将A和B相加,我认为应该是grp = df.groupby(['A', 'B', df['D'] > 0]).cumsum() df['step1'].mask(df['step1'] == 0).combine_first(df['receipts_adjustments_sales']).groupby(grp).cumsum() - gr1zzly be4r
1
分组有点难,但是我会弄明白并在我的问题中发布。 - gr1zzly be4r
显示剩余3条评论

1

另一个与Scott的回答类似:

groups = df['D'].ne(0).cumsum()
df['new'] = (df['C'].where(df['D'].eq(0), df['D'])
     .groupby(groups)
     .cumsum()
)

如果您能逐步解释这个逻辑,那将会很有帮助。 - Scott Boston
@ScottBoston 那会复制你所写的 :-) - Quang Hoang

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