Python pandas cumsum 每当遇到 0 时重置

18

我有一个由0和1组成的矩阵,希望对每一列进行cumsum运算,当观察到0时重置为0。例如,如果我们有以下矩阵:

df = pd.DataFrame([[0,1],[1,1],[0,1],[1,0],[1,1],[0,1]],columns = ['a','b'])
print(df)
   a  b
0  0  1
1  1  1
2  0  1
3  1  0
4  1  1
5  0  1

我希望得到的结果是:

print(df)
   a  b
0  0  1
1  1  2
2  0  3
3  1  0
4  2  1
5  0  2

然而,当我尝试使用 df.cumsum() * df 时,我能够正确地识别出0元素,但计数器并没有重置:

print(df.cumsum() * df)
   a  b
0  0  1
1  1  2
2  0  3
3  2  0
4  3  4
5  0  5
4个回答

30

你可以使用:

a = df != 0
df1 = a.cumsum()-a.cumsum().where(~a).ffill().fillna(0).astype(int)
print (df1)
   a  b
0  0  1
1  1  2
2  0  3
3  1  0
4  2  1
5  0  2

为什么这个有效?我不确定它是否适用于我的情况。 - Veggiet
1
@Veggiet - 请查看此链接,其中有类似的解决方案和说明。 - jezrael
1
要在列之间执行此操作,而不是在行之间执行,请改用以下代码:a = df.T != 0 df1= (a.cumsum()-a.cumsum().where(~a).ffill().fillna(0).astype(int)).T - Anonymous

9

试试这个

df = pd.DataFrame([[0,1],[1,1],[0,1],[1,0],[1,1],[0,1]],columns = ['a','b'])
df['groupId1']=df.a.eq(0).cumsum()
df['groupId2']=df.b.eq(0).cumsum()
New=pd.DataFrame()
New['a']=df.groupby('groupId1').a.transform('cumsum')
New['b']=df.groupby('groupId2').b.transform('cumsum')

New
Out[1184]: 
   a  b
0  0  1
1  1  2
2  0  3
3  1  0
4  2  1
5  0  2

1
好的,我明白了,你每次遇到0都在创建单独的分组,然后在每个分组内进行累加。很有道理。谢谢! - nanojohn
@nanojohn 是的,已经为此创建了groupid。不客气~ - BENY
这看起来很不错,而且灵活。 - Veggiet

2
你可以尝试以下朴素但可靠的方法。
对于每一列,创建一个分组来进行计数。当行之间出现连续的值差异时,分组开始,并在值保持不变时持续存在:(x != x.shift()).cumsum()
例如:
    a   b
0   1   1
1   2   1
2   3   1
3   4   2
4   4   3
5   5   3

使用 pd.DataFrameapplygroupby 方法,在每列内部计算组的累积总和,可以用一行代码得到具有零重置的累积和:

import pandas as pd

df = pd.DataFrame([[0,1],[1,1],[0,1],[1,0],[1,1],[0,1]], columns = ['a','b'])

cs = df.apply(lambda x: x.groupby((x != x.shift()).cumsum()).cumsum())
print(cs)

   a  b
0  0  1
1  1  2
2  0  3
3  1  0
4  2  1
5  0  2

1
一种稍微有些hacky的方法是先找到所有0的索引,然后在进行cumsum之前将这些索引对应的值设置为它们的相反数:
import pandas as pd
df = pd.DataFrame([[0,1],[1,1],[0,1],[1,0],[1,1],[0,1]],columns = ['a','b'])
z = np.where(df['b']==0)
df['b'][z[0]] = -z[0]
df['b'] = np.cumsum(df['b'])
df

   a  b
0  0  1
1  1  2
2  0  3
3  1  0
4  1  1
5  0  2

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