免责声明我是trrex的作者
对于完全匹配的情况,解决此问题的一种方法是使用Trie,如评论中所述。trrex是一个制作 Trie-Regex(正则表达式格式的 Trie)的库,可以与 Python 的正则表达式引擎一起使用:
import random
import pandas as pd
import trrex as tx
import re
df = pd.read_csv('jeopardy-small.csv')
with open('words-sample') as infile:
words = [line.strip() for line in infile]
tuples = [(random.randint(1, 250), sentence) for sentence in df['question']]
def fun_kislyuk(ws, ts):
return {t[0] for t in ts if any(w in t[1] for w in ws)}
def fun_trrex(ws, ts):
pattern = re.compile(tx.make(ws, left='', right=''))
return {i for i, s in ts if pattern.search(s)}
if __name__ == "__main__":
print(fun_trrex(words, tuples) == fun_kislyuk(words, tuples))
输出
True
上述功能的时间安排是:
%timeit fun_trrex(words, tuples)
11.3 ms ± 34.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit fun_kislyuk(words, tuples)
67.5 ms ± 1.75 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
数据是来自 jeopardy 的大约 2000 个问题和 500 个随机选择的单词的列表。你可以在这里找到重现实验的资源。
更新
如果您添加评论中提到的分组策略,时间改进会增加,以下是功能:
def fun_grouping_trrex(ws, ts):
pattern = re.compile(tx.make(ws, left='', right=''))
groups = defaultdict(list)
for i, s in ts:
groups[i].append(s)
return {i for i, vs in groups.items() if any(pattern.search(v) for v in vs)}
和时间:
%timeit fun_trrex(words, tuples)
11.2 ms ± 61.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit fun_grouping_trrex(words, tuples)
4.96 ms ± 320 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit fun_kislyuk(words, tuples)
67.4 ms ± 1.47 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
分组+ trrex的方法使您的性能提高了大约10 倍。但是对最后一个结果持保留态度,因为它非常依赖于数据集。