如何并行化pd.concat中的for循环,实现模糊字符串匹配Top N结果输出
基于模糊字符串匹配合并大型数据集的并行优化
需要基于不完全匹配的字符串列合并两个大型数据集,宽表数据集可以辅助比仅用字符串距离更精准地判定最佳匹配,但首先需要为每个字符串返回多个Top匹配结果。
可复现示例代码如下:
def example_function(idx, string, comparisons, n): tup = process.extract(string, comparisons, limit = n) df2_index = [i[2] for i in tup] scores = [i[1] for i in tup] return pd.DataFrame({ "df1_index": [idx] * n, "df2_index": df2_index, "score": scores }) import pandas as pd from fuzzywuzzy import process s1 = pd.Series(["two apples", "one orange", "my banana", "red grape", "huge kiwi"]) s2 = pd.Series(["a couple of apples", "old orange", "your bananas", "purple grape", "tropical fruit"]) pd.concat([example_function(index, value, s2, 2) for index, value in s1.items()]).reset_index()
一直没能成功将该函数并行化,目前找到的最接近的方案是多进程实现,但即便使用starmap也没有得到正确结果。应该存在简单的实现方法,但还没找到可行方案。
接受任何代码优化建议,并行处理在这个场景下是非常合适的解决方案:经预估如果串行执行该逻辑需要耗时约4-5小时。
更新内容
感谢各位提供的解决方案,实际场景下df1有7000行,df2有70000行,以下是用df1前20行遍历匹配df2全量70000行的性能测试结果:
- 原dataframe concat方案:96秒
- 字典chain方案:90秒
- 基于dask的4进程并行方案:77秒
- 替换fuzzywuzzy为rapidfuzz:6.73秒
- rapidfuzz搭配dask 4进程并行:5.29秒
最终优化后的代码如下:
from dask.distributed import Client from dask import delayed from rapidfuzz import process, fuzz from itertools import chain client = Client(n_workers = 4, processes = False) def example_function(idx, string, comparisons, n): tup = process.extract(string, comparisons, scorer = fuzz.WRatio, limit = n) return [{'idx': idx, 'index2': t[2], 'score': t[1]} for t in tup] jobs = [delayed(example_function)(index, value, t3, 20) for index, value in t1.items()] data = delayed(jobs) df = pd.DataFrame.from_records(chain(*data.compute())) print(df) client.close()
并行处理带来的性能提升没有达到预期,可能是该函数的并行配置没有优化到最优,也可能是随着迭代次数增加并行优势会更明显。不管怎样它确实带来了性能提升,所以在解决方案中采用了该方案,感谢各位的帮助。
内容的提问来源于stack exchange,提问作者Chad S
相关产品推荐
相关产品推荐

