我有一个与此类似的数据框:
df = pd.DataFrame({'col1': ['a', 'a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'c'],
'col2': [1, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, 2, 2],
'col3': [1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0],
'desired': [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1]})
我想在col3
上应用滚动总和,当col1
或col2
更改或col3
变为零时,该值会重置。
请注意,总和偏移1个单元格。这意味着新(col1, col2)
组合的期望值将始终为零。
下面的代码演示了所需的逻辑。但是,下面的数据集需要将近4分钟。
des = []
count = 0
for i in range(1, len(df)):
des.append(count)
if (df.iloc[i-1].col1 == df.iloc[i].col1) & \
(df.iloc[i-1].col2 == df.iloc[i].col2) & \
(df.iloc[i-1].col3 == 1):
count += 1
else:
count = 0
des.append(0)
df['desired'] = des
要测试的更大数据集:https://www.dropbox.com/s/hbafcq6hdkh4r9r/test.csv?dl=0
答案 0 :(得分:2)
首先使用io.emit()
shift
,然后连续计算groupby
:
1
答案 1 :(得分:1)
由于OP希望获得 rolling (滚动)计数,因此这似乎表明他们希望处理可能在df
中不同位置重复的小组,而又不希望将所有小组混在一起(例如groupby
可以。)
在问题陈述中,听起来更像是带有复位的累积操作。这是一类相对容易矢量化的问题,根本不涉及groupby
。
这是使用numpy
的一种方式:
def cum_count(df, groupcols, zerocol):
a = df[groupcols].values
c = df[zerocol].values
# find indices to reset the cumulative count
r0 = np.concatenate(([True], np.any(a[1:] != a[:-1], axis=1)))
r1 = np.concatenate(([True], c[:-1] == 0))
reset = np.nonzero(r0 + r1)[0]
# offset: values to subtract at reset indices
off = np.concatenate(([0], np.diff(reset)))
# we add 1 everywhere except at reset indices
delt = np.ones(df.shape[0], dtype=int)
delt[reset] -= off
return np.cumsum(delt) - 1
这是一个极端的例子:
df = pd.DataFrame([
['a', 1, 1, 0],
['a', 1, 1, 1],
['a', 1, 1, 2],
['b', 1, 1, 0],
['b', 1, 1, 1],
['b', 1, 1, 2],
['a', 1, 1, 0],
['a', 1, 1, 1],
['a', 1, 1, 2],
], columns='col1 col2 col3 desired'.split())
c = custom_cum_count(df, 'col1 col2'.split(), 'col3')
assert np.all(c == df['desired'])
print(c)
# out
[0 1 2 0 1 2 0 1 2]