Python 列的滚动累加和';s值,直到满足条件为止

Python 列的滚动累加和';s值,直到满足条件为止,python,pandas,rolling-computation,cumsum,Python,Pandas,Rolling Computation,Cumsum,我有一个叫做“df”的数据帧。看起来是这样的: a 0 2 1 3 2 0 3 5 4 1 5 3 6 1 7 2 8 2 9 1 a a_cumm_sum 0 2 2 1 3 5 2 0 0 3 5 5 4 1 1 5 3 4 6 1 5 7 2 2 8 2 4 9 1 5 我想生成一个累加和

我有一个叫做“df”的数据帧。看起来是这样的:

    a
0   2   
1   3   
2   0   
3   5   
4   1   
5   3   
6   1   
7   2   
8   2   
9   1   
    a   a_cumm_sum
0   2   2
1   3   5
2   0   0
3   5   5
4   1   1
5   3   4
6   1   5
7   2   2
8   2   4
9   1   5
我想生成一个累加和列,其中:

  • 将“a”列的内容累加起来
  • 直到它得到“5”的总和
  • 当总和达到“5”时,将总和重置为0,并继续总和过程
我希望数据帧看起来像这样:

    a
0   2   
1   3   
2   0   
3   5   
4   1   
5   3   
6   1   
7   2   
8   2   
9   1   
    a   a_cumm_sum
0   2   2
1   3   5
2   0   0
3   5   5
4   1   1
5   3   4
6   1   5
7   2   2
8   2   4
9   1   5
在数据框中,“a_cumm_summ”列包含累积和的结果


有人知道我怎样才能做到这一点吗?我在论坛上搜寻过。例如,我看到了类似的问题,但它们不符合我的确切要求。

你可以得到总和,地板除以5。然后从下一行的累积和中减去楼层除法的结果,乘以5:

c = df['a'].cumsum()
g = 5 * (c // 5)
df['a_cumm_sum'] = (c.shift(-1) - g).shift().fillna(df['a']).astype(int)
df
Out[1]: 
   a  a_cumm_sum
0  2           2
1  3           5
2  0           0
3  5           5
4  1           1
5  3           4
6  1           5
7  2           2
8  2           4
9  1           5

解决方案2(更稳健):

根据特伦顿的评论,一个好的、多样化的样本数据集对于找出这些类型问题的牢不可破的逻辑有很大帮助。第一次使用一个好的样本数据集,我可能会想出一个更好的解决方案。下面是一个解决方案,它克服了Trenton在评论中提到的示例数据集。如图所示,当您必须处理结转时,需要处理更多的条件。在大型数据集上,这仍然比for循环更具性能,但矢量化逻辑要困难得多:

df = pd.DataFrame({'a': {0: 2, 1: 4, 2: 1, 3: 5, 4: 1, 5: 3, 6: 1, 7: 2, 8: 2, 9: 1}})
c = df['a'].cumsum()
g = 5 * (c // 5)
df['a_cumm_sum'] = (c.shift(-1) - g).shift().fillna(df['a']).astype(int)
over = (df['a_cumm_sum'].shift(1) - 5)
df['a_cumm_sum'] = df['a_cumm_sum'] - np.where(over > 0, df['a_cumm_sum'] - over, 0).cumsum()
s = np.where(df['a_cumm_sum'] < 0, df['a_cumm_sum']*-1, 0).cumsum()
df['a_cumm_sum'] = np.where((df['a_cumm_sum'] > 0) & (s > 0), s + df['a_cumm_sum'],
                              df['a_cumm_sum'])
df['a_cumm_sum'] = np.where(df['a_cumm_sum'] < 0, df['a_cumm_sum'].shift() + df['a'], df['a_cumm_sum'])
df
Out[2]: 
   a  a_cumm_sum
0  2         2.0
1  4         6.0
2  1         1.0
3  5         6.0
4  1         1.0
5  3         4.0
6  1         5.0
7  2         2.0
8  2         4.0
9  1         5.0
df=pd.DataFrame({'a':{0:2,1:4,2:1,3:5,4:1,5:3,6:1,7:2,8:2,9:1})
c=df['a'].cumsum()
g=5*(c//5)
df['a_cumm_sum']=(c.shift(-1)-g.shift().fillna(df['a']).astype(int)
over=(df['a_cumm_sum'].移位(1)-5)
df['a_cumm_sum']=df['a_cumm_sum']-np.其中(大于0,df['a_cumm_sum']-over,0).cumsum()
s=np.其中(df['a_cumm_sum']<0,df['a_cumm_sum']*-1,0).cumsum()
df['a_cumm_sum']=np.其中((df['a_cumm_sum']>0)和(s>0),s+df['a_cumm_sum'],
df[‘金额’)
df['a___________________________________________________________
df
出[2]:
总数
0  2         2.0
1  4         6.0
2  1         1.0
3  5         6.0
4  1         1.0
5  3         4.0
6  1         5.0
7  2         2.0
8  2         4.0
9  1         5.0

分配可以与条件组合。代码如下:

    a   cumsum  new
0   2   2       2
1   3   5       5
2   0   5       0
3   5   10      5
4   1   11      1
5   3   14      4
6   1   15      5
7   2   17      2
8   2   19      4
9   1   20      5
将numpy导入为np
作为pd进口熊猫
a=[2,3,0,5,1,3,1,2,2,1]
df=pd.DataFrame(a,列=[“a”])
df[“cumsum”]=df[“a”].cumsum()
df[“新”]=df[“总和”]%5
df[“new”][(df[“cumsum”]/5)=(df[“cumsum”]/5).astype(int))和(df[“a”!=0)]=5
df
结果如下:

    a   cumsum  new
0   2   2       2
1   3   5       5
2   0   5       0
3   5   10      5
4   1   11      1
5   3   14      4
6   1   15      5
7   2   17      2
8   2   19      4
9   1   20      5
工作:
基本上,取余数作为5的累积和。在实际总和为5的情况下,也变为零。因此,对于这些情况,请检查
value/5==int(value/5)
。然后,删除实际值为零的情况。

编辑: 正如特伦顿·麦金尼(Trenton McKinney)在评论中指出的那样,OP很可能希望在总和超过5时将其重置为0。这使得定义成为一个重复,这通常很难用pandas/numpy来实现(见David的解决方案)。在这种情况下,我建议使用
numba
来加速for循环


另一种选择:使用
groupby

[78]中的
:df.groupby((df['a'].cumsum()%5==0.shift().fillna(False.cumsum()).cumsum()
出[78]:
A.
0  2
1  5
2  0
3  5
4  1
5  4
6  5
7  2
8  4
9  5

您可以尝试使用此for循环:

lastvalue = 0
newcum = []
for i in df['a']:
    if lastvalue >= 5:
        lastvalue = i
    else:
        lastvalue += i
    newcum.append(lastvalue)
df['a_cum_sum'] = newcum
print(df)
输出:

   a  a_cum_sum
0  2          2
1  3          5
2  0          0
3  5          5
4  1          1
5  3          4
6  1          5
7  2          2
8  2          4
9  1          5

上面的for循环遍历
a
列,当累计和等于或大于5时,它将其重置为
0
,然后添加
a
列的值
i
,但如果累计和小于5,它只添加
a
列的值
i
(迭代器).

像这样的条件使得矢量化方法在这里很难使用,我可能会考虑使用
numba
,这将使您加快速度,并将其作为一个显式循环来编写。对于在编写此注释时显示的解决方案,我使用
导入熊猫作为pd来测试每个解决方案;输入numpy作为np;np.random.seed(365);df=pd.DataFrame({'a':[np.random.randint(5)表示范围(3000000)])
。虽然所有的解决方案都适用于OP的测试数据,但当两行的
cumsum
大于5时,只有from正确地将
cumsum
重置为0。我不是投反对票的人,但是,我猜这是因为,虽然这可能解决问题,但这不是一个好的
cumsum
解决方案,因为带有
pandas
for循环是
反模式
。正如您从其他解决方案中所看到的,有更有效、矢量化的方法来解决问题。但是,我认为这是不正确的。@TrentonMcKinney是的,我刚刚发布了一个使用
for
循环的解决方案,这可能不是最好的。我支持我对
for循环的评论,但是+1是唯一满足条件的解决方案
将累计总和重置为0
。其他解决方案仅适用于测试数据,但当2个数字的
cumsum
大于5时,其他解决方案将失败。@TrentonMcKinney感谢您对我的投票:-)是的,这不是很有效,但工作方式最一致:-)此解决方案似乎适用于测试数据,但是,如果连续数字之和大于5,则它似乎无法正常工作。例如,给定
[2,4,1]
的值,解决方案应该是
[2,6,1]
,但是,此解决方案返回
[2,6,2]
,因为超过5的余数(在本例中为1)在累积和中结转。将总和重置为0,条件未得到正确满足。@TrentonMcKinney查看我的更新答案。如果使用
np.random.seed(365)运行它;df=pd.DataFrame({'a':[np.random。