Python实现两数据集列相似匹配的方法优化及ID获取咨询
解决方案
- 核心优化逻辑:提前构建df2的name到对应number的映射字典,用O(1)的字典查找替代pd.merge的O(n log n)排序连接操作,万级规模数据集下速度可提升10~100倍,无需在匹配完成后再做关联操作。
实现代码
步骤1:预处理df2构建映射字典
如果需要保留匹配name对应的所有df2编号,用如下方式构建字典:
import difflib as dl import numpy as np import pandas as pd # 原始数据集 df1 = pd.DataFrame([[1,'one'],[2,'two'],[3,'three'],[4,'four'],[5,'five'],[7,'seven']], columns=['number', 'name']) df2 = pd.DataFrame([[1,'one'],[2,'two'],[3,'three'],[4,'four'],[5,'five'],[55,'five'],[555,'five'],[6,'six'],[7,'seven'],[77,'seven'],[777,'seven'],[8,'eight']], columns=['number', 'name']) # 构建name到所有对应number的映射字典,仅需遍历一次df2 df2_name_to_nums = df2.groupby('name')['number'].agg(list).to_dict()
如果你的去重逻辑是保留每个匹配name的最后一个df2编号,可直接构建更高效的单值映射字典:
# 仅保留每个name对应的最后一个number,和现有去重keep="last"逻辑完全对齐 df2_name_last_num = df2.drop_duplicates(subset=['name'], keep='last').set_index('name')['number'].to_dict()
步骤2:改造apply逻辑直接返回匹配结果+对应df2编号
以单值映射字典为例,代码如下:
def get_matches_with_id(name): # 先获取相似匹配的name matched_names = dl.get_close_matches(name, df2['name'], cutoff=0.75, n=5) # 直接返回包含匹配name和对应df2编号的元组列表 return [(matched_name, df2_name_last_num[matched_name]) for matched_name in matched_names] df1['match_result'] = df1['name'].apply(get_matches_with_id)
步骤3:展开结果完成去重
# 展开列表匹配结果 df1 = df1.explode('match_result').reset_index(drop=True) # 拆分匹配结果为两列 df1[['duplicates', 'df2_number']] = pd.DataFrame(df1['match_result'].tolist(), index=df1.index) # 去重、清理冗余列 df1 = df1.drop_duplicates(subset=['duplicates'], keep='last').drop(columns=['match_result']).reset_index(drop=True)
最终输出示例
| number | name | duplicates | df2_number |
|---|---|---|---|
| 1 | one | one | 1 |
| 2 | two | two | 2 |
| 3 | three | three | 3 |
| 4 | four | four | 4 |
| 5 | five | five | 555 |
| 7 | seven | seven | 777 |
进阶优化
如果数据规模超过10万条,可将difflib替换为fuzzywuzzy[speedup]库,底层为C实现的相似匹配算法,匹配速度可再提升数倍。
内容的提问来源于stack exchange,提问作者Daniil Yefimov
相关产品推荐
相关产品推荐

