如何降低使用fuzzywuzzy去除文本部分重复项的代码运行耗时?
原代码的核心性能问题是存在O(n²)的全量匹配冗余:每一行文本都要和全量数据集做一次模糊匹配计算,2000行数据就会产生400万次匹配运算,加上fuzzywuzzy默认的纯Python编辑距离计算效率偏低,最终导致耗时过高。
替换高性能依赖库,减少单次匹配耗时
优先替换fuzzywuzzy为同接口的高性能实现rapidfuzz,底层是C++开发,匹配速度是原库的5~10倍,同时安装python-Levenshtein依赖加速编辑距离计算,安装命令:pip install rapidfuzz python-Levenshtein,仅需修改导入语句即可适配,无需调整业务逻辑。
另外原代码调用process.extract时仅需要前2个匹配结果,可新增limit=2参数,避免返回不必要的匹配结果,减少多余计算。过滤无效匹配,降低计算量
两个文本如果token_set_ratio得分超过80,长度差不可能过大,可提前过滤长度差超过30%的文本对,无需进入匹配计算;也可提前将文本按token倒排索引,仅对共享至少2个相同token的文本对做匹配,大幅减少无效计算。优化匹配逻辑,避免O(n²)全量匹配
调整逻辑先将所有文本按长度从长到短排序,遍历过程中仅将当前文本和已经保留的文本列表做匹配:如果当前文本和所有已保留文本的相似度都低于阈值,就加入保留列表,否则直接跳过(因为已保留的文本更长,符合你要保留长文本的需求)。优化后无需全量两两匹配,也无需最后再做set去重,逻辑更简洁,计算量大幅降低。可选:局部敏感哈希(LSH)预分组
万级以上数据量可引入LSH算法,先把相似文本哈希到同一个桶中,仅在桶内做匹配,可将时间复杂度降到接近O(n)。
优化后示例代码
from rapidfuzz import fuzz, process rows = ["I have your Body Wash and I wonder if it contains animal ingredients. Also, which animal ingredients? I prefer not to use product with animal ingredients.","This also doesn't have the ADA on there. Is this a fake toothpaste an imitation of yours?","I have your Body Wash and I wonder if it contains animal ingredients. I prefer not to use product with animal ingredients.","I didn't see the ADA stamp on this box. I just want to make sure it was still safe to use?","Hello, I was just wondering if the new toothpaste is ADA approved? It doesn’t say on the packaging","Hello, I was just wondering if the new toothpaste is ADA approved? It doesn’t say on the box."] threshold = 80 # 先按文本长度从长到短排序,保证优先保留长文本 sorted_rows = sorted(rows, key=lambda x: len(x), reverse=True) clean = [] for row in sorted_rows: if not clean: clean.append(row) continue # 仅和已保留的文本匹配,低于阈值直接返回空 match_res = process.extractOne(row, clean, scorer=fuzz.token_set_ratio, score_cutoff=threshold) # 没有匹配到相似文本就加入保留列表 if not match_res: clean.append(row)
上述优化后的代码在2000行数据集上的耗时可降到原代码的1/10以下,叠加长度过滤等规则后耗时还能进一步降低。
内容的提问来源于stack exchange,提问作者Shrumo

