如何在Python中高效使用fuzzywuzzy?大数据量相似度计算优化及进度监控
优化大规模字符串匹配效率与进度跟踪方案
一、提升运行效率的方法
1. 替换为高性能匹配库
fuzzywuzzy是纯Python实现,处理百万级数据效率极低,建议改用rapidfuzz(C语言优化的模糊匹配库,速度提升10-100倍)。针对你只需要Top1匹配结果的场景,用extractOne替代extract进一步减少计算量。
from rapidfuzz import process, fuzz # 预处理:提取Banana.Bname的唯一值,减少重复匹配 unique_bnames = Banana['Bname'].unique() # 定义匹配函数 def match_single_name(aname): # WRatio是综合了大小写、截断等场景的通用评分器,可根据需求替换为fuzz.ratio等 match_result = process.extractOne(aname, unique_bnames, scorer=fuzz.WRatio) return pd.Series([match_result[0], match_result[1]])
2. 并行化处理
利用多进程/多线程分散计算压力,推荐用swifter库自动适配并行策略(CPU密集型用多进程,IO密集型用多线程),无需手动管理进程池:
import swifter # 并行应用匹配函数,自动利用多核CPU Apple[['Bname', 'similarity']] = Apple['Aname'].swifter.apply(match_single_name)
如果不想依赖swifter,也可以手动用multiprocessing实现:
from multiprocessing import Pool # 将匹配逻辑转为可被进程池调用的函数 def match_func(aname): res = process.extractOne(aname, unique_bnames, scorer=fuzz.WRatio) return (res[0], res[1]) # 根据CPU核心数创建进程池 with Pool() as pool: # 批量处理Apple.Aname的所有值 match_results = pool.map(match_func, Apple['Aname'].tolist()) # 将结果合并回原DataFrame Apple[['Bname', 'similarity']] = pd.DataFrame(match_results, index=Apple.index)
3. 预处理减少匹配基数
如果Banana.Bname存在大量重复值,先提取唯一值(如上述代码中的unique_bnames),能将匹配次数从70万降至唯一值数量,大幅减少计算量。
4. 优化匹配算法
如果业务允许,可选择更轻量的匹配逻辑:
- 若只需前缀/后缀匹配,直接用字符串的
startswith()/endswith()方法,速度比模糊匹配快几个数量级; - 若必须用模糊匹配,可先通过n-gram索引过滤候选集(比如提取每个字符串的2-gram,只对包含相同n-gram的Bname计算相似度),缩小匹配范围。
二、跟踪运行进度
1. 用tqdm添加进度条
tqdm是常用的进度跟踪库,能直观显示循环或任务的处理进度:
from tqdm import tqdm Bname = [] similarity = [] total_rows = len(Apple) # 给迭代器包裹tqdm,显示实时进度 for aname in tqdm(Apple['Aname'], total=total_rows, desc="匹配进度"): match_result = process.extractOne(aname, unique_bnames) Bname.append(match_result[0]) similarity.append(match_result[1]) Apple['Bname'] = Bname Apple['similarity'] = similarity
2. swifter内置进度条
使用swifter时,只需设置progress_bar=True即可显示处理进度:
Apple[['Bname', 'similarity']] = Apple['Aname'].swifter.apply(match_single_name, progress_bar=True)
3. 手动打印进度(无依赖方案)
如果不想安装额外库,可每隔N次循环打印进度信息:
total_rows = len(Apple) Bname = [] similarity = [] for idx, aname in enumerate(Apple['Aname']): match_result = process.extractOne(aname, unique_bnames) Bname.append(match_result[0]) similarity.append(match_result[1]) # 每处理1万行打印一次进度 if idx % 10000 == 0: progress = (idx / total_rows) * 100 print(f"已处理 {idx}/{total_rows} 行,进度: {progress:.2f}%")
内容的提问来源于stack exchange,提问作者leilei
相关产品推荐
相关产品推荐

