【问题标题】:Cumulative count reset on condition累计计数重置条件
【发布时间】:2017-09-30 15:22:28
【问题描述】:

我有一个类似这样的数据框:

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 上应用滚动总和,当col1col2 发生变化或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

【问题讨论】:

  • col3第一行为0的情况,能不能加个case,没有图片请难复制。
  • 注意:您示例中的最后一个 desired 值应为 1。这也是我理解的应该基于你的解释。但是您为演示逻辑而提供的代码给出了0。我怀疑您应该在循环后更改为des.append(count)
  • 还不清楚您是想要col3 的累积总和还是累积计数(非零)。对于col3 in {0, 1},两者相同,但其他值呢?问题陈述表明sum,但示例代码表明count

标签: python pandas


【解决方案1】:

首先使用groupbyshift,然后计算连续的1

a = df.groupby(['col1','col2'])['col3'].shift().fillna(0).eq(1)
b = a.cumsum()

df['desired'] = b-b.where(~a).ffill().fillna(0).astype(int)

print (df.head(20))
      col1  col2  col3  desired
0   100055     1     1        0
1   100055     1     0        1
2   100055     1     0        0
3   100055     1     0        0
4   100055     1     0        0
5   100055     1     0        0
6   100055     1     0        0
7   100055     1     0        0
8   100055     1     0        0
9   100055     1     0        0
10  100055     1     1        0
11  100055     1     1        1
12  100055     1     0        2
13  100055     1     1        0
14  100055     1     1        1
15  100055     1     0        2
16  100055     1     0        0
17  100055     1     1        0
18  100055     1     0        1
19  100055     1     1        0

【讨论】:

  • 抱歉,但这并不完全有效,因为在同一 (col1, col2) 对中的 col3 变为零后,所需的列不会重置回 1。我会发布一个更大的数据集。
  • 你能用你的大 df 改变你的样本数据吗?我觉得你的问题真的很复杂,所以mcve 真的很有必要。谢谢。
  • @jezrael 我已经添加了可以运行的代码,我希望它能够展示我需要的逻辑。
  • 请检查编辑的答案,我测试输出,它和你的循环解决方案一样。
【解决方案2】:

由于 OP 想要 滚动 计数,这似乎表明他们想要处理可能在 df 中不同位置重复的组,而不是将它们混为一谈(如 @987654322 @ 会做)。

从问题陈述来看,这听起来更像是一个带有重置的累积操作。那是一类比较容易向量化的问题,完全不涉及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]

【讨论】:

    猜你喜欢
    • 2018-03-28
    • 1970-01-01
    • 2019-07-03
    • 1970-01-01
    • 1970-01-01
    • 2022-12-07
    • 1970-01-01
    • 2019-03-28
    • 1970-01-01
    相关资源
    最近更新 更多