如何加速pandas字符串函数?

7

我正在使用pandas向量化的str.split()方法来提取在“~”分割后返回的第一个元素。我还尝试使用df.apply()与lambda和str.split()来产生等效结果。但是使用%timeit时,我发现df.apply()的性能比向量化版本更快。

我阅读过关于向量化的所有内容似乎都表明第一个版本应该具有更好的性能。请问有人可以解释一下为什么会出现这种情况吗?示例:


     id     facility      
0   3466     abc~24353  
1   4853     facility1~3.4.5.6   
2   4582     53434_Facility~34432~cde   
3   9972     facility2~FACILITY2~343
4   2356     Test~23 ~FAC1  

上述数据框大约有500,000行,我也测试了大约1,000,000行,结果类似。以下是一些示例输入和输出:
向量化
In [1]: %timeit df['facility'] = df['facility'].str.split('~').str[0]
1.1 s ± 54.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Lambda Apply

In [2]: %timeit df['facility'] = df['facility'].astype(str).apply(lambda facility: facility.split('~')[0])
650 ms ± 52.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

有人知道我为什么会遇到这种情况吗?
谢谢!


你为什么认为str.split是矢量化的?在Pandas / Numpy中,矢量化通常意味着连续的内存块。 df['facility']object类型的,这只是一堆指针。 - jpp
我认为这是因为这个网站:https://jakevdp.github.io/PythonDataScienceHandbook/03.10-working-with-strings.html - ddx
我认为这个网站对“向量化”这个术语非常慷慨。 - jpp
我尝试改进这个lambda函数的原因是因为我遇到了一个之前使用groupby和filter来根据条件过滤行的lambda函数。当我将其更改为使用布尔索引来删除这些行时,我看到了显著的性能提升。 - ddx
1个回答

17
Pandas字符串方法只是“矢量化”的,这意味着您不必自己编写循环。实际上并没有进行任何并行处理,因为字符串(特别是正则表达式问题)本质上是难以(或不可能?)并行化的。如果您真的想要速度,您应该回退到Python。
%timeit df['facility'].str.split('~', n=1).str[0]
%timeit [x.split('~', 1)[0] for x in df['facility'].tolist()]

411 ms ± 10.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
132 ms ± 302 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

要了解何时循环比Pandas函数更快的更多信息,请查看For loops with pandas - When should I care?

至于为什么 apply 更快,我认为 apply 应用的函数(即 str.split)比在 Series.str.split 中进行的字符串分割要轻量得多。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接