如果列数是动态的,如何从数据框中过滤数据?

时间:2016-07-26 06:05:24

标签: python numpy pandas dataframe

我有一个如下数据框

    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     ......

4 个答案:

答案 0 :(得分:4)

使用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

答案 1 :(得分:4)

  • 使用filter获取您关注的列。
  • abs().lt(1)以查找小于1的单元格。
  • all(1)查找所有Value小于1的行。
df[df.filter(regex=r'Value').abs().lt(1).all(1)]

enter image description here

时序

<强>结论

likeregexlt<

最快的解决方案是两者兼顾:

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

enter image description here

<强>击穿

enter image description here

答案 2 :(得分:0)

如果您不想过滤列名称(即使它们带有前缀),您也可以使用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

答案 3 :(得分:0)

您可以使用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