【问题标题】:Get dataframe rows where every T sequence of columns there's 1 N times获取数据帧行,其中每个 T 列序列有 1 N 次
【发布时间】:2018-07-31 08:16:03
【问题描述】:

如何获取 每个序列 的 5 列中 至少 3 倍于第一的 Dataframe 的行? 用 1 和 0 填充的数据框(无缺失值)。

示例:

此外,由于我需要检查数百万行和数十个列,因此快速接近会很有帮助。

【问题讨论】:

    标签: python pandas numpy dataframe matrix


    【解决方案1】:

    创建一个宽度为 5 的滚动总和宽度,查看从第 5 到末尾的所有列,如果值始终为 3 或更高,则选择它们:

    rolling_sum = df.rolling(5, min_periods=1, axis=1).sum()
    select = (rolling_sum.iloc[:, 4:] >= 3).all(axis=1)
    
    In [92]: df
    Out[92]: 
       0  1  2  3  4  5  6  7  8  9
    0  0  0  0  0  0  0  0  0  0  0
    1  0  1  0  0  1  0  1  1  0  0
    2  0  1  0  1  1  0  0  1  0  0
    3  0  1  1  1  0  1  1  1  1  1
    4  0  1  0  1  1  1  0  0  1  1
    5  0  0  1  1  1  0  1  1  1  0
    
    In [94]: (df.rolling(5, min_periods=1, axis=1).sum().iloc[:, 4:] >= 3).all(axis=1)
    Out[94]: 
    0    False
    1    False
    2    False
    3     True
    4     True
    5     True
    dtype: bool
    

    【讨论】:

    • 一种简单的方法是将所有不同于 1 的值设置为 0 (df[df != 1] = 0),然后运行相同的算法。也许在df 的副本上执行此操作以保留原始值。
    【解决方案2】:

    将底层数组数据重塑为3D,使最后一个轴具有5元素,每个元素代表5的块,然后沿该轴求和,得到每个块的总和,最后使用@987654324 @reduce 沿第二个轴表示原始数据帧中的每一行 -

    df['result'] = (df.values.reshape(-1,df.shape[1]//5,5).sum(2)>=3).any(1)
    

    为了提高性能,您可能希望使用布尔数组 :df.values==1 而不是 df.values。

    示例运行 -

    In [41]: df
    Out[41]: 
       0  1  2  3  4  5  6  7  8  9
    0  0  1  1  0  0  1  0  0  0  1
    1  0  0  0  0  0  0  1  0  1  1
    2  0  1  1  0  0  1  1  0  0  1
    3  1  1  1  1  0  0  0  1  0  1
    4  0  1  1  1  0  1  1  1  1  0
    5  0  0  0  0  1  0  0  1  1  1
    6  0  0  1  0  1  1  0  0  0  1
    
    In [42]: df['result'] = (df.values.reshape(-1,df.shape[1]//5,5).sum(2)>=3).any(1)
    
    In [43]: df
    Out[43]: 
       0  1  2  3  4  5  6  7  8  9  result
    0  0  1  1  0  0  1  0  0  0  1   False
    1  0  0  0  0  0  0  1  0  1  1    True
    2  0  1  1  0  0  1  1  0  0  1    True
    3  1  1  1  1  0  0  0  1  0  1    True
    4  0  1  1  1  0  1  1  1  1  0    True
    5  0  0  0  0  1  0  0  1  1  1    True
    6  0  0  1  0  1  1  0  0  0  1   False
    

    如果列数不是5的倍数,我们可以使用np.add.reduceat -

    idx = np.arange(0,df.shape[1],5)
    df['result'] = (np.add.reduceat(df.values, idx, axis=1)>=3).any(1)
    

    millions rows and tens of cols 的时间安排 -

    In [99]: np.random.seed(0)
        ...: a = (np.random.rand(1000000,20)>0.6).astype(int)
        ...: df = pd.DataFrame(a)
    
    # Solution from this post
    In [101]: %timeit (df.values.reshape(-1,df.shape[1]//5,5).sum(2)>=3).any(1)
    10 loops, best of 3: 65.3 ms per loop
    
    # @w-m's soln
    In [102]: %timeit (df.rolling(5, min_periods=1, axis=1).sum().iloc[:, 4:] >= 3).all(axis=1)
    1 loop, best of 3: 8.04 s per loop
    

    【讨论】:

      猜你喜欢
      • 2020-11-23
      • 1970-01-01
      • 1970-01-01
      • 2010-10-01
      • 2020-05-17
      • 1970-01-01
      • 1970-01-01
      • 2018-07-27
      • 1970-01-01
      相关资源
      最近更新 更多