你可以尝试使用Aho-Corasick算法。在平均情况下,它的时间复杂度为O(n+m+p)
,其中n
是搜索字符串的长度,m
是被搜索文本的长度,p
是输出匹配项的数量。
Aho-Corasick算法通常用于在输入文本(“干草堆”)中查找多个模式(针)。
pyahocorasick是该算法的C语言实现的Python包装器。
让我们比较一下使用其他方法的速度有多快。下面是一个基准测试,显示using_aho_corasick
在一个包含50,000行数据的DataFrame测试案例中比原始方法(问题中显示的方法)快30倍以上:
| | speed factor | ms per loop |
| | compared to orig | |
|--------------------+------------------+-------------|
| using_aho_corasick | 30.7x | 140 |
| using_regex | 2.7x | 1580 |
| orig | 1.0x | 4300 |
In [89]: %timeit using_ahocorasick(col, lst)
10 loops, best of 3: 140 ms per loop
In [88]: %timeit using_regex(col, lst)
1 loop, best of 3: 1.58 s per loop
In [91]: %timeit orig(col, lst)
1 loop, best of 3: 4.3 s per loop
以下是用于基准测试的设置。它还验证输出是否与orig
返回的结果相匹配:
import numpy as np
import random
import pandas as pd
import ahocorasick
import re
random.seed(321)
def orig(col, lst):
mask = np.logical_or.reduce([col.str.contains(i, regex=False, case=False)
for i in lst])
return mask
def using_regex(col, lst):
"""https://dev59.com/mVYM5IYBdhLWcg3wpRfa#48590850 (Alex Riley)"""
esc_lst = [re.escape(s) for s in lst]
pattern = '|'.join(esc_lst)
mask = col.str.contains(pattern, case=False)
return mask
def using_ahocorasick(col, lst):
A = ahocorasick.Automaton(ahocorasick.STORE_INTS)
for word in lst:
A.add_word(word.lower())
A.make_automaton()
col = col.str.lower()
mask = col.apply(lambda x: bool(list(A.iter(x))))
return mask
N = 50000
lst = [''.join([chr(random.randint(0, 256)) for _ in range(5)]) for _ in range(100)]
strings = [''.join([chr(random.randint(0, 256)) for _ in range(20)]) for _ in range(N)]
strings = [_ if random.randint(0, 99) < 10 else _+random.choice(lst) for _ in strings]
col = pd.Series(strings)
expected = orig(col, lst)
for name, result in [('using_regex', using_regex(col, lst)),
('using_ahocorasick', using_ahocorasick(col, lst))]:
status = 'pass' if np.allclose(expected, result) else 'fail'
print('{}: {}'.format(name, status))
A.iter
在调用col.apply
时被调用,其中col
是一个 pandas Series。这与使用 pandas DataFrame 做的事情并没有太大区别(甚至可能完全相同)。使用apply
的性能与简单的 Python 循环大致相同,但您仍将获得使用 Aho-Corasick 算法的好处。 - unutbu