【问题标题】:How to count the number of occurences before a particular value in dataframe python?如何计算数据框python中特定值之前的出现次数?
【发布时间】:2020-01-15 10:15:00
【问题描述】:

我有一个如下的数据框:

A   B   C
1   1   1
2   0   1
3   0   0
4   1   0
5   0   1
6   0   0
7   1   0

我想要df['B'] 在以下条件下出现的零的数量:

if(df['B']<df['C']):
  #count number of zeroes in df['B'] until it sees 1.

预期输出:

A   B   C  output
1   1   1   Nan
2   0   1   1
3   0   0   Nan
4   1   0   Nan
5   0   1   1
6   0   1   0
7   1   0   Nan

我不知道如何制定计数部分。非常感谢任何帮助

【问题讨论】:

    标签: python pandas dataframe cumsum


    【解决方案1】:

    在您的反向系列上使用一些掩蔽和 groupby。这假设二进制数据(只有 0 和 1)


    m = df['B'][::-1].eq(0)
    d = m.groupby(m.ne(m.shift()).cumsum()).cumsum().sub(1)
    d[::-1].where(df['B'] < df['C'])
    

    0    NaN
    1    1.0
    2    NaN
    3    NaN
    4    1.0
    5    0.0
    6    NaN
    Name: B, dtype: float64
    

    还有一种基于numpy 的快速方法

    def zero_until_one(a, b):
        n = a.shape[0]    
        x = np.flatnonzero(a < b)
        y = np.flatnonzero(a == 1)    
        d = np.searchsorted(y, x)
        r = y[d] - x - 1
        out = np.full(n, np.nan)
        out[x] = r   
        return out
    
    zero_until_one(df['B'], df['C'])
    

    array([nan,  1., nan, nan,  1.,  0., nan])
    

    性能

    df = pd.concat([df]*10_000)
    
    %timeit chris1(df)
    19.3 ms ± 348 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    %timeit yatu(df)
    12.8 ms ± 54.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    %timeit zero_until_one(df['B'], df['C'])
    2.32 ms ± 31.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    

    【讨论】:

    • numpy 函数的好主意,只是猜测 numba 可能更快
    【解决方案2】:

    IIUC 的一种方法是使用自定义分组器并与 groupby.cumcount 聚合:

    c1 = df.B.lt(df.C)
    g = df.B.eq(1).cumsum()
    df['out'] = c1.groupby(g).cumcount(ascending=False).shift().where(c1).sub(1)
    

    print(df)
    
       A  B  C  out
    0  1  1  1  NaN
    1  2  0  1  1.0
    2  3  0  0  NaN
    3  4  1  0  NaN
    4  5  0  1  1.0
    5  6  0  1  0.0
    6  7  1  0  NaN
    

    【讨论】:

      【解决方案3】:

      让我们推入一行

      df.groupby(df.B.iloc[::-1].cumsum()).cumcount(ascending=False).shift(-1).where(df.B<df.C)
      Out[80]: 
      0    NaN
      1    1.0
      2    NaN
      3    NaN
      4    1.0
      5    0.0
      6    NaN
      dtype: float64
      

      【讨论】:

        猜你喜欢
        • 2021-09-24
        • 1970-01-01
        • 2020-09-12
        • 1970-01-01
        • 1970-01-01
        • 2022-12-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多