搜索元组列表以查找匹配子字符串的算法方法?
Posted
技术标签:
【中文标题】搜索元组列表以查找匹配子字符串的算法方法?【英文标题】:Algorithmic way to search a list of tuples for a matching substring? 【发布时间】:2021-03-08 06:25:47 【问题描述】:我有一个元组列表,大约有 100k 个条目。每个元组由一个 id 和一个字符串组成,我的目标是列出元组的 id,其字符串包含给定子字符串列表中的子字符串。 我目前的解决方案是通过集合理解,ids可以重复。
tuples = [(id1, 'cheese trees'), (id2, 'freezy breeze'),...]
vals = ['cheese', 'flees']
ids = i[0] for i in tuples if any(val in i[1] for val in vals)
output: id1
有没有一种算法可以更快地做到这一点?我对精确的子字符串匹配感兴趣,也可能对近似匹配感兴趣。我在这里主要追求的是一种算法,它比理解提供速度优势。
【问题讨论】:
什么是近似子串匹配? 什么是“算法方式”? 有一个叫做fuzzy matching的东西可以进行近似的字符串匹配。我知道的一种 Python 实现是FuzzyWuzzy。 @martineau 虽然 FuzzyWuzzy 对单个字符串进行近似字符串匹配,但它并没有提高处理大量字符串的速度,这对我来说是重点。 两个小问题:(1)您可以通过多处理来加快速度。 (2) 如果您按 id 分组,那么您只需要处理一个组,直到它找到第一个匹配项(可能会节省一些时间)。 【参考方案1】:免责声明我是trrex的作者
对于精确匹配,解决此问题的一种方法是使用Trie,如 cmets 中所述。 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)
数据是一个包含大约 2000 个来自 jeopardy 的问题和 500 个随机选择的单词的列表。您可以找到here 复制实验的资源。
更新
如果添加cmets中提到的分组策略时间改进增加,以下是功能:
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)
grouping + trrex 的方法可以让您的性能提高大约 10 倍。但对最后一个结果持保留态度,因为它非常依赖于数据集。
【讨论】:
以上是关于搜索元组列表以查找匹配子字符串的算法方法?的主要内容,如果未能解决你的问题,请参考以下文章
Excel - 需要从数组中搜索列表单元格的子字符串,无法获得索引/匹配工作吗?