熊猫dataframe.query到SQL'Like',而无需使用engine ='python'

时间:2019-12-03 00:27:12

标签: python sql python-3.x pandas

在Pandas dataframe.query()中复制SQL“ LIKE”条件有很多相关示例。但是,我发现的所有示例本质上都归结为利用column.str.contains(),这需要附加的engine='python'

我正在处理非常大的数据集,频繁查询和复杂的WHERE条件。在我的用例中,使用python引擎带来的性能提升很快。

是否存在使用标准(和SUPER FAST)numexpr引擎的语法等效项?我知道我可以使用.query()之外的其他方法,但是对于复杂的查询,它们可能变得非常冗长。

1 个答案:

答案 0 :(得分:1)

首先设置一些示例数据:

import pandas as pd
import string
import numexpr as ne

n = 10_000_000
k = 5
df = pd.DataFrame({'col1': pd.np.random.choice(list(string.ascii_lowercase),size=n*k).view((pd.np.str_,k)),
                   'col2': pd.np.random.random(n)})

为了使containsnumexpr引擎一起使用,您必须添加.values。但是,查询仍然很慢,原因是不是 .values操作,如对.values引擎使用和不使用python的比较所见:

%timeit df.query("col1.str.contains('a').values", engine='numexpr')
#1 loop, best of 3: 3.48 s per loop

%timeit df.query("col1.str.contains('a')", engine='python')
#1 loop, best of 3: 3.55 s per loop

%timeit df.query("col1.str.contains('a').values", engine='python')
#1 loop, best of 3: 3.52 s per loop

对于相对简单的查询,numexpr的性能优势可忽略不计(另请参见react bindings)。如我们所见,.values仅增加了60毫秒:

%timeit df.query("col2.values < .5", engine='numexpr')
1 loop, best of 3: 363 ms per loop

%timeit df.query("col2 < .5", engine='numexpr')
1 loop, best of 3: 298 ms per loop

%timeit df.query("col2 < .5", engine='python')
1 loop, best of 3: 299 ms per loop


https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#performance-of-query,但未在熊猫中实现。一种解决方法-当然不是很优雅-解决方法是将熊猫的值复制到数组中,然后使用 numexpr.evaluate 进行布尔索引:

%timeit df.query("col1.str.contains('a').values & (col2 < .5)", engine='numexpr')
#1 loop, best of 3: 3.53 s per loop

%timeit df.query("col1.str.contains('a') & (col2 < .5)", engine='python')
#1 loop, best of 3: 3.45 s per loop

%%timeit
arr1 = df.col1.to_numpy(bytes)
arr2 = df.col2.to_numpy()
df[ne.evaluate("contains(arr1, 'a') & (arr2 < .5)")]
#1 loop, best of 3: 1.18 s per loop

这大约是pandas版本的3倍,其中包括复制到数组和布尔索引的开销。仅ne.evaluate("contains(arr1, 'a') & (arr2 < .5)")只需280毫秒。