pandas:用操作符链过滤DataFrame的行

大多数pandas操作都可以通过操作符链接来实现( groupbyaggregateapply等),但我发现过滤行的唯一方法是通过正常的括号索引

 df_filtered = df[df['column'] == value] 

这是没有吸引力的,因为它需要我把df赋值给一个variables,然后才能过滤它的值。 有什么更像以下?

 df_filtered = df.mask(lambda x: x['column'] == value) 

我不完全确定你想要什么,最后一行代码也没有帮助,但无论如何:

“链接”过滤是通过“链接”布尔指数中的条件来完成的。

 In [96]: df Out[96]: ABCD a 1 4 9 1 b 4 5 0 2 c 5 5 1 0 d 1 3 9 6 In [99]: df[(df.A == 1) & (df.D == 6)] Out[99]: ABCD d 1 3 9 6 

如果你想链方法,你可以添加自己的掩码方法,并使用该方法。

 In [90]: def mask(df, key, value): ....: return df[df[key] == value] ....: In [92]: pandas.DataFrame.mask = mask In [93]: df = pandas.DataFrame(np.random.randint(0, 10, (4,4)), index=list('abcd'), columns=list('ABCD')) In [95]: df.ix['d','A'] = df.ix['a', 'A'] In [96]: df Out[96]: ABCD a 1 4 9 1 b 4 5 0 2 c 5 5 1 0 d 1 3 9 6 In [97]: df.mask('A', 1) Out[97]: ABCD a 1 4 9 1 d 1 3 9 6 In [98]: df.mask('A', 1).mask('D', 6) Out[98]: ABCD d 1 3 9 6 

@lodagro的答案很好。 我将通过泛化掩码函数来扩展它:

 def mask(df, f): return df[f(df)] 

那么你可以做这样的东西:

 df.mask(lambda x: x[0] < 0).mask(lambda x: x[1] > 0) 

filter可以使用pandas查询进行链接:

 df = pd.DataFrame( np.random.randn(30,3), columns = ['a','b','c']) df_filtered = df.query('a>0').query('0<b<2') 

filter也可以组合在一个查询中:

 df_filtered = df.query('a>0 and 0<b<2') 

pandas.DataFrame.query
query完全是为了这个目的。 考虑数据框df

 import pandas as pd import numpy as np np.random.seed([3,1415]) df = pd.DataFrame( np.random.randint(10, size=(10, 5)), columns=list('ABCDE') ) df ABCDE 0 0 2 7 3 8 1 7 0 6 8 6 2 0 2 0 4 9 3 7 3 2 4 3 4 3 6 7 7 4 5 5 3 7 5 9 6 8 7 6 4 7 7 6 2 6 6 5 8 2 8 7 5 8 9 4 7 6 1 5 

让我们使用query来筛选D > B所有行

 df.query('D > B') ABCDE 0 0 2 7 3 8 1 7 0 6 8 6 2 0 2 0 4 9 3 7 3 2 4 3 4 3 6 7 7 4 5 5 3 7 5 9 7 6 2 6 6 5 

我们链接

 df.query('D > B').query('C > B') # equivalent to # df.query('D > B and C > B') # but defeats the purpose of demonstrating chaining ABCDE 0 0 2 7 3 8 1 7 0 6 8 6 4 3 6 7 7 4 5 5 3 7 5 9 7 6 2 6 6 5 

我有同样的问题,除了我想把标准合并成OR条件。 Wouter Overmeire给出的格式将标准组合成一个AND条件,这样就必须满足这两个条件:

 In [96]: df Out[96]: ABCD a 1 4 9 1 b 4 5 0 2 c 5 5 1 0 d 1 3 9 6 In [99]: df[(df.A == 1) & (df.D == 6)] Out[99]: ABCD d 1 3 9 6 

但是我发现,如果你用(... == True)包装每个条件,并且用pipe道连接标准,那么条件在OR条件下被合并,只要它们中的任何一个为真就满足:

 df[((df.A==1) == True) | ((df.D==6) == True)] 

我的答案与其他人类似。 如果你不想创build一个新的函数,你可以使用已经为你定义的pandas。 使用pipe道方法。

 df.pipe(lambda d: d[d['column'] == value]) 

如果你想要应用所有常见的布尔模板以及一个通用的模板,你可以将以下内容放在一个文件中,然后简单地将它们全部赋值如下:

 pd.DataFrame = apply_masks() 

用法:

 A = pd.DataFrame(np.random.randn(4, 4), columns=["A", "B", "C", "D"]) A.le_mask("A", 0.7).ge_mask("B", 0.2)... (May be repeated as necessary 

这有点不好意思,但如果你不断地根据filter切换和改变数据集,它可以使事情变得更清洁。 在gen_mask函数中还有一个由Daniel Velkov调用的通用滤波器,你可以在lambda函数中使用它,否则如果需要的话。

要保存的文件(我使用masks.py):

 import pandas as pd def eq_mask(df, key, value): return df[df[key] == value] def ge_mask(df, key, value): return df[df[key] >= value] def gt_mask(df, key, value): return df[df[key] > value] def le_mask(df, key, value): return df[df[key] <= value] def lt_mask(df, key, value): return df[df[key] < value] def ne_mask(df, key, value): return df[df[key] != value] def gen_mask(df, f): return df[f(df)] def apply_masks(): pd.DataFrame.eq_mask = eq_mask pd.DataFrame.ge_mask = ge_mask pd.DataFrame.gt_mask = gt_mask pd.DataFrame.le_mask = le_mask pd.DataFrame.lt_mask = lt_mask pd.DataFrame.ne_mask = ne_mask pd.DataFrame.gen_mask = gen_mask return pd.DataFrame if __name__ == '__main__': pass 

从版本0.18.1开始 , .loc方法接受一个可供select的callable。 与lambda函数一起,您可以创build非常灵活的可链式filter:

 import numpy as np import pandas as pd df = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=list('ABCD')) df.loc[lambda df: df.A == 80] # equivalent to df[df.A == 80] but chainable df.sort_values('A').loc[lambda df: df.A > 80].loc[lambda df: df.B > df.A] 

如果你只是在过滤,你也可以省略.loc

如果您将列设置为索引进行search,则可以使用DataFrame.xs()进行截面分析。 这不像query回答的那样通用,但在某些情况下可能会有用。

 import pandas as pd import numpy as np np.random.seed([3,1415]) df = pd.DataFrame( np.random.randint(3, size=(10, 5)), columns=list('ABCDE') ) df # Out[55]: # ABCDE # 0 0 2 2 2 2 # 1 1 1 2 0 2 # 2 0 2 0 0 2 # 3 0 2 2 0 1 # 4 0 1 1 2 0 # 5 0 0 0 1 2 # 6 1 0 1 1 1 # 7 0 0 2 0 2 # 8 2 2 2 2 2 # 9 1 2 0 2 1 df.set_index(['A', 'D']).xs([0, 2]).reset_index() # Out[57]: # ADBCE # 0 0 2 2 2 2 # 1 0 2 1 1 0