【问题标题】:How to filter data from a data frame when the number of columns are dynamic?当列数是动态的时,如何从数据框中过滤数据?
【发布时间】:2016-07-26 06:05:23
【问题描述】:

我有一个如下所示的数据框

    A_Name  B_Detail  Value_B  Value_C   Value_D ......
0   AA      X1        1.2      0.5       -1.3    ......
1   BB      Y1        0.76     -0.7      0.8     ......
2   CC      Z1        0.7      -1.3      2.5     ......
3   DD      L1        0.9      -0.5      0.4     ......
4   EE      M1        1.3      1.8       -1.3    ......
5   FF      N1        0.7      -0.8      0.9     ......
6   GG      K1        -2.4     -1.9      2.1     ......

这只是一个数据框示例,我可以有 n 列,例如 (Value_A, Value_B, Value_C, .... Value_N)

现在我想过滤所有列(Value_A,Value_B,Value_C,...)的绝对值小于 1 的所有行。

如果您的列数有限,您可以通过简单地在数据框中的列上放置“和”条件来过滤数据,但我无法弄清楚在这种情况下该怎么做。

我不知道此类列的数量是多少,我唯一知道此类列将以“值”为前缀。

在上述情况下,输出应该是这样的

    A_Name  B_Detail  Value_B  Value_C   Value_D ......
1   BB      Y1        0.76     -0.7      0.8     ......
3   DD      L1        0.9      -0.5      0.4     ......
5   FF      N1        0.7      -0.8      0.9     ......

【问题讨论】:

    标签: python numpy pandas dataframe


    【解决方案1】:

    使用filterabsall 创建mask 然后boolean indexing

    mask = (df.filter(like='Value').abs() < 1).all(axis=1)
    print (mask)
    0    False
    1     True
    2    False
    3     True
    4    False
    5     True
    6    False
    dtype: bool
    
    print (df[mask])
      A_Name B_Detail  Value_B  Value_C  Value_D
    1     BB       Y1     0.76     -0.7      0.8
    3     DD       L1     0.90     -0.5      0.4
    5     FF       N1     0.70     -0.8      0.9
    

    时序中的所有组合:

    #len df = 70k, 5 columns
    df = pd.concat([df]*10000).reset_index(drop=True)
    
    In [47]: %timeit (df[(df.filter(like='Value').abs() < 1).all(axis=1)])
    100 loops, best of 3: 7.48 ms per loop
    
    In [48]: %timeit (df[df.filter(regex=r'Value').abs().lt(1).all(1)])
    100 loops, best of 3: 7.02 ms per loop
    
    In [49]: %timeit (df[df.filter(like='Value').abs().lt(1).all(1)])
    100 loops, best of 3: 7.02 ms per loop
    
    In [50]: %timeit (df[(df.filter(regex=r'Value').abs() < 1).all(axis=1)])
    100 loops, best of 3: 7.3 ms per loop
    

    #len df = 70k, 5k columns
    df = pd.concat([df]*10000).reset_index(drop=True)
    df = pd.concat([df]*1000, axis=1)
    #only for testing, create unique columns names
    df.columns = df.columns.str[:-1] + [str(col) for col in list(range(df.shape[1]))]
    print (df)
    
    In [75]: %timeit ((df[(df.filter(like='Value').abs() < 1).all(axis=1)]))
    1 loop, best of 3: 10.3 s per loop
    
    In [76]: %timeit ((df[(df.filter(regex=r'Value').abs() < 1).all(axis=1)]))
    1 loop, best of 3: 10.3 s per loop
    
    In [77]: %timeit (df[df.filter(regex=r'Value').abs().lt(1).all(1)])
    1 loop, best of 3: 10.4 s per loop
    
    In [78]: %timeit (df[df.filter(like='Value').abs().lt(1).all(1)])
    1 loop, best of 3: 10.1 s per loop
    

    【讨论】:

    • :-) 几乎一样
    • 由于某种原因,时间上有细微的差别。最终测试它。
    • 两个区别是like vs regexlt vs &lt;
    • likeregex 快,但 lt&lt; 快得多。添加时间。
    【解决方案2】:
    • 使用filter 获取您关心的列。
    • abs().lt(1) 查找小于 1 的单元格。
    • all(1) 查找所有 Value 小于 1 的行。

    df[df.filter(regex=r'Value').abs().lt(1).all(1)]
    


    时间

    结论

    likeregexlt&lt;

    最快的解决方案是结合两者的优点:

    df[df.filter(like='Value').abs().lt(1).all(1)]
    

    细分

    【讨论】:

    • 你说得对,我在包含 5000 列的大型数据框中添加了计时;)
    【解决方案3】:

    如果您不想过滤列名(即使它们带有前缀),您也可以使用ix

    >>> df[df.ix[:,2:].abs().lt(1).all(1)]
          A_Name B_Detail  Value_B  Value_C  Value_D
    1     BB       Y1     0.76     -0.7      0.8
    3     DD       L1     0.90     -0.5      0.4
    5     FF       N1     0.70     -0.8      0.9
    

    这假设您所有的“价值”列都在您的“详细信息”列之后。

    而且由于每个人都在进行基准测试,所以速度更快:

    In [7]: %timeit df[df.ix[:,2:].abs().lt(1).all(1)]                                                              
    1000 loops, best of 3: 803 µs per loop
    
    In [8]: %timeit df[df.filter(like='Value').abs().lt(1).all(1)]
    1000 loops, best of 3: 939 µs per loop
    

    【讨论】:

      【解决方案4】:

      您可以使用str.contains 匹配列,然后使用apply()lambda

      cols = df.columns[df.columns.str.contains('Value')]
      df[df[cols].apply(lambda x: abs(x) < 1).sum(axis=1) == len(cols)]
      

      输出:

              A_Name  B_Detail    Value_B     Value_C     Value_D
      1       BB      Y1          0.76        -0.7        0.8
      3       DD      L1          0.90        -0.5        0.4
      5       FF      N1          0.70        -0.8        0.9
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-05
        • 1970-01-01
        • 1970-01-01
        • 2017-02-05
        • 1970-01-01
        • 2014-07-26
        • 1970-01-01
        • 2019-06-12
        相关资源
        最近更新 更多