一尘不染

将多个过滤器应用于pandas DataFrame或Series的有效方法

algorithm

我有一种情况,用户想要将多个过滤器应用于Pandas
DataFrame或Series对象。本质上,我想有效地将​​用户在运行时指定的一堆过滤(比较操作)链接在一起。

过滤器应为可加性的(又称每个过滤器应缩小结果)。

我当前正在使用,reindex()但这每次都会创建一个新对象并复制基础数据(如果我正确理解了文档)。因此,这在过滤大型Series或DataFrame时可能效率很低。

我认为使用apply()map()或类似的方法可能更好。我对Pandas来说还很陌生,因此仍然想尽一切办法。

TL; DR

我想采用以下形式的字典,并将每个操作应用于给定的Series对象,并返回一个“过滤后的” Series对象。

relops = {'>=': [1], '<=': [1]}

长例子

我将从当前的示例开始,仅过滤单个Series对象。以下是我当前正在使用的功能:

   def apply_relops(series, relops):
        """
        Pass dictionary of relational operators to perform on given series object
        """
        for op, vals in relops.iteritems():
            op_func = ops[op]
            for val in vals:
                filtered = op_func(series, val)
                series = series.reindex(series[filtered])
        return series

用户向字典提供他们要执行的操作:

>>> df = pandas.DataFrame({'col1': [0, 1, 2], 'col2': [10, 11, 12]})
>>> print df
>>> print df
   col1  col2
0     0    10
1     1    11
2     2    12

>>> from operator import le, ge
>>> ops ={'>=': ge, '<=': le}
>>> apply_relops(df['col1'], {'>=': [1]})
col1
1       1
2       2
Name: col1
>>> apply_relops(df['col1'], relops = {'>=': [1], '<=': [1]})
col1
1       1
Name: col1

同样,上述方法的“问题”是,我认为中间步骤之间存在很多可能不必要的数据复制。

另外,我想对此进行扩展,以便传入的字典可以包括要操作的列,并根据输入字典过滤整个DataFrame。但是,我假设该系列的所有工作都可以轻松扩展到DataFrame。


阅读 236

收藏
2020-07-28

共1个答案

一尘不染

熊猫(和numpy)允许使用布尔索引,这将更加高效:

In [11]: df.loc[df['col1'] >= 1, 'col1']
Out[11]: 
1    1
2    2
Name: col1

In [12]: df[df['col1'] >= 1]
Out[12]: 
   col1  col2
1     1    11
2     2    12

In [13]: df[(df['col1'] >= 1) & (df['col1'] <=1 )]
Out[13]: 
   col1  col2
1     1    11

如果要为此编写辅助函数,请考虑以下方面:

In [14]: def b(x, col, op, n): 
             return op(x[col],n)

In [15]: def f(x, *b):
             return x[(np.logical_and(*b))]

In [16]: b1 = b(df, 'col1', ge, 1)

In [17]: b2 = b(df, 'col1', le, 1)

In [18]: f(df, b1, b2)
Out[18]: 
   col1  col2
1     1    11

更新:pandas 0.13针对此类用例提供了一种查询方法,假设列名是有效的标识符,则可以进行以下工作(并且对于大型框架,在幕后使用numexpr可能更为有效):

In [21]: df.query('col1 <= 1 & 1 <= col1')
Out[21]:
   col1  col2
1     1    11
2020-07-28