Pandas - 为什么用 str.extract 循环比 str.extractall 循环快

Pandas - why looping with str.extract is faster than one str.extractall

我有一个包含字符串的数据框(约 10 万行),我需要从中提取多个项目并为其创建新列。

示例数据

import pandas as pd
import re

s = pd.Series(['param1=1&param2=&param3=ena&param4=n2oi3-284&',
            'param1=2&param2=2iot&param3=&param4=&',
            'param1=3&param2=afv&param3=39&param4=4obgg942n&',
            'param1=4&param2=&param3=1291&param4=0g2n48a&'])

我可以将正则表达式 re.compile(r"=(.*?)&)"str.extractall 结合使用,然后解压生成的数据帧 select,并附加我想要的列。

match 0 1 2 3
0 1 NaN ena n2oi3-284
1 2 2iot NaN NaN
2 3 afv 39 4obgg942n
3 4 NaN 1291 0g2n48a

但是当我测试它时,它比在字典中为每个参数创建唯一的正则表达式要慢,例如 r"1=(.*?)&",然后遍历该字典并为每个正则表达式使用列分配。

params = {'param1': re.compile(r"1=(.*?)&"),
        'param2': re.compile(r"2=(.*?)&"),
        'param3': re.compile(r"3=(.*?)&"),
        'param4': re.compile(r"4=(.*?)&")}

for k, rx in params.items():
    df[k] = s.str.extract(rx, expand=False)

当我使用 %%timeit 时,循环遍历正则表达式字典并为每个创建一个新列似乎比使用 str.extractall 更快(忽略任何类型的列分配/结果数据帧操作)。

rx = re.compile(r"=(.*?)&")

%%timeit -n 100
s.str.extractall(rx)

每个循环 2.56 ms ± 407 µs(7 次运行的平均值 ± 标准偏差,每次 100 次循环)

%%timeit -n 100
for rx in params.values():
    s.str.extract(rx, expand=False)

每个循环 791 µs ± 152 µs(7 次运行的平均值 ± 标准偏差,每次 100 次循环)

这是为什么?我是否错误地计时功能/比较不同的东西?遍历该列一次不应该比遍历该列 4 次更快吗?

str.extract and str.extractall doesn't say anything about this. Looking at the source code for extractall versus extract 的文档,我无法确定为什么一个比另一个快。

谢谢!

根据源代码 extractall 使用列表并附加到这些列表,如果经常使用,可能会很慢。

extractall 尝试保持动态,因为它将捕获所有可能的匹配项,因此也会遍历整个字符串,extract 将在第一个匹配项上 return。如果你只关心第一场比赛,你也可以只使用 extract 可能是这样的:

s.str.extract(re.compile(r"param1=(.*?)&*param2=(.*?)&*param3=(.*?)&*param4=(.*?)&"))

所以也许 extract 更适合您的用例?