【问题标题】:Efficient method to count consecutive positive values in pandas dataframe计算熊猫数据框中连续正值的有效方法
【发布时间】:2021-07-16 14:14:50
【问题描述】:

我试图计算 pandas 数据框中每一列的连续积极事件的数量。 DSM 在此处提供的解决方案 - Counting consecutive positive value in Python array 适用于给定系列。

import pandas as pd

a = [0,1,0,1,1,0,0,0,1,1,0,1,0]
b = [0,0,0,0,1,1,0,1,1,1,0,0,0]

series = pd.Series(a)

consecutiveCount(series).values

数组([0, 1, 0, 1, 2, 0, 0, 0, 1, 2, 0, 1, 0], dtype=int64)

但是,当我尝试对具有多列的数据框执行此操作时,我得到以下信息。

df = pd.DataFrame({'a':a, 'b':b})
consecutiveCount(df)

ValueError: Grouper for '<class 'pandas.core.frame.DataFrame'>' not 1-dimensional

如果我遍历每一列,它可以工作,但速度很慢。是否有一种矢量化方式来一次处理整个数据帧?

谢谢!

【问题讨论】:

  • 你的df有多大?
  • 适中 - 52 行,60 列。

标签: python pandas


【解决方案1】:

unstacked 系列中仅一次 使用consecutiveCounts。然后,堆栈回数据帧。

使用 DSM 的 consecutiveCount,为简单起见,我在此处将其命名为 c

>>> c = lambda y: y * (y.groupby((y != y.shift()).cumsum()).cumcount() + 1)
>>> c(df.unstack()).unstack().T

    a   b
0   0   0
1   1   0
2   0   0
3   1   0
4   2   1
5   0   2
6   0   0
7   0   1
8   1   2
9   2   3
10  0   0
11  1   0
12  0   0

时间

# df2 is (65, 40)
df2 = pd.concat([pd.concat([df]*20, axis=1)]*5).T.reset_index(drop=True).T.reset_index(drop=True)

%timeit c(df2.unstack()).unstack().T
5.54 ms ± 296 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit df2.apply(c)
82.5 ms ± 2.19 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

【讨论】:

  • 哇!这真的提高了速度!太棒了,感谢您的帮助。现在我只需要了解为什么它会这么快。
【解决方案2】:

您可以尝试apply 方法。这可能会给您带来更好的结果:

df.apply(consecutiveCount)

【讨论】:

  • 谢谢!我觉得自己像个白痴一样不去尝试——我想我还没有很好地适应熊猫的思维方式。这将时间从 171 毫秒减少到 164 毫秒。这个函数在我的算法中被锤击并且真的减慢了速度。我想知道是否有更快的方法来进行连续计数?
【解决方案3】:

改编自@cs95's answer

a = pd.Series([-1, 2, 15, 3, 45, 5, 23, 0, 6, -4, -8, -5, 3, 
-9, -7, -36, -71, -2, 25, 47, -8])

def pos_neg_count(a):
    v = a.ge(0).ne(a.ge(0).shift()).cumsum()
    vals = v.groupby(v).count().values
    cols = ['pos', 'neg'] if a[0] >= 0 else ['neg', 'pos']
    try:
        result = pd.DataFrame(vals.reshape(-1, 2), columns=cols)
    except ValueError:
        vals = np.insert(vals, len(vals), 0)
        result = pd.DataFrame(vals.reshape(-1, 2), columns=cols)
    return result

pos_neg_count(a)
#       neg pos
#   0     1   8
#   1     3   1
#   2     5   2
#   3     1   0

【讨论】:

    猜你喜欢
    • 2020-07-24
    • 1970-01-01
    • 1970-01-01
    • 2020-10-29
    • 2021-03-31
    • 2017-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多