我有一个场景,用户希望对Pandas数据帧或序列对象应用多个过滤器。本质上,我想有效地将用户在运行时指定的一系列过滤(比较操作)链接在一起。
过滤器应该是加性的(也就是说每一个应用都应该缩小结果范围)。
我目前正在使用reindex()
,但这会每次创建一个新对象并复制底层数据(如果我正确理解文档)。因此,在筛选大型序列或数据帧时,这可能非常低效。
我认为使用apply()
、map()
或类似的方法可能会更好。我对熊猫还不太熟悉,所以我还是想把我的头包在所有的东西上。
我想要一个如下形式的字典,并将每个操作应用于给定的序列对象,并返回一个“过滤”的序列对象。
relops = {'>=': [1], '<=': [1]}
我将从一个当前的例子开始,只过滤一个序列对象。下面是我当前使用的函数:
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
同样,我上述方法的“问题”在于,我认为中间步骤中可能存在大量不必要的数据复制。
此外,我还想扩展它,以便传入的字典可以包含要操作的列,并根据输入字典筛选整个数据帧。但是,我假设对这个系列有效的东西可以很容易地扩展到一个数据帧。
最简单的解决方案:
使用:
另一个示例要筛选属于2018年2月的值的数据帧,请使用以下代码
熊猫(和numpy)允许boolean indexing,这将更有效:
如果要为此编写助手函数,请考虑以下内容:
更新:pandas 0.13 has a query method对于这些类型的用例,假设列名是有效的标识符,则可以执行以下操作(对于大型框架,在幕后使用numexpr时效率更高):
链接条件会产生长线,pep8不鼓励这样做。 使用.query方法会强制使用字符串,这很强大,但不符合语法,而且不是很动态。
一旦每个过滤器就位,一种方法是
logical在上操作并且速度很快,但不接受两个以上的参数,这是由functools.reduce处理的。
请注意,这仍然有一些冗余:a)快捷方式不会在全局级别上发生;b)每个单独的条件都在整个初始数据上运行。不过,我希望这对许多应用程序都足够有效,而且非常可读。
相关问题 更多 >
编程相关推荐