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¶m2=¶m3=ena¶m4=n2oi3-284&',
'param1=2¶m2=2iot¶m3=¶m4=&',
'param1=3¶m2=afv¶m3=39¶m4=4obgg942n&',
'param1=4¶m2=¶m3=1291¶m4=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
更适合您的用例?
我有一个包含字符串的数据框(约 10 万行),我需要从中提取多个项目并为其创建新列。
示例数据
import pandas as pd
import re
s = pd.Series(['param1=1¶m2=¶m3=ena¶m4=n2oi3-284&',
'param1=2¶m2=2iot¶m3=¶m4=&',
'param1=3¶m2=afv¶m3=39¶m4=4obgg942n&',
'param1=4¶m2=¶m3=1291¶m4=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
更适合您的用例?