如何在两个Pandas DataFrame间模糊匹配公司名并保留相似度得分
问题解决步骤
1. 修正相似度函数的参数错误
原函数存在两处问题:一是调用sequence_uniqueness时缺失token2frequency参数;二是token2frequency应为存储token出现次数的字典,而非固定数值。修正后的函数如下:
def sequence_uniqueness(seq, token2frequency): # 用get避免token不存在时的KeyError,默认频率设为1 return sum(1 / token2frequency.get(t, 1)**0.5 for t in seq) def name_similarity(a, b, token2frequency): a_tokens = set(a.split()) b_tokens = set(b.split()) a_uniq = sequence_uniqueness(a_tokens, token2frequency) b_uniq = sequence_uniqueness(b_tokens, token2frequency) intersection = a_tokens.intersection(b_tokens) # 避免除以0或无交集的情况,返回0分 if not intersection or a_uniq == 0 or b_uniq == 0: return 0.0 return sequence_uniqueness(intersection, token2frequency) / (a_uniq * b_uniq) ** 0.5
2. 生成所有公司名组合
通过交叉连接生成两个DataFrame中所有可能的名字配对,为后续计算相似度做准备:
import pandas as pd # 添加临时键实现交叉连接 mwe1['temp_key'] = 1 mwe2['temp_key'] = 1 # 生成笛卡尔积形式的所有组合 all_combinations = pd.merge(mwe1, mwe2, on='temp_key').drop('temp_key', axis=1)
3. 计算全局token频率
收集所有公司名的token并统计出现次数,为相似度计算提供频率数据:
from collections import Counter # 合并所有名字并拆分token all_names = pd.concat([mwe1['company_name'], mwe2['salesforce_name']]) all_tokens = [] for name in all_names: all_tokens.extend(name.split()) # 统计每个token的出现频率 token2frequency = Counter(all_tokens)
4. 批量计算相似度得分
使用apply遍历每一行,对配对的公司名计算相似度:
all_combinations['similarity_score'] = all_combinations.apply( lambda row: name_similarity(row['company_name'], row['salesforce_name'], token2frequency), axis=1 )
5. 筛选最优匹配结果
按company_name分组,保留每组中相似度最高的记录:
# 获取每组相似度最高的行索引 best_match_indices = all_combinations.groupby('company_name')['similarity_score'].idxmax() # 提取最优匹配结果 best_matches = all_combinations.loc[best_match_indices] # 查看核心结果 print(best_matches[['company_name', 'salesforce_name', 'revenue', 'CEO', 'similarity_score']])
大规模数据优化提示
针对5万+5千的数据集,直接生成2.5亿行组合会占用大量内存,可通过以下方式优化:
- 预处理名字:统一大小写、去除标点、替换常见缩写(如"Co."→"Company")
- 使用更快的相似度库:如
rapidfuzz替代自定义函数,计算效率提升数倍 - 预过滤无效组合:提前排除长度差异过大、无共同token的名字对
- 分块处理:将大DataFrame拆分为小块,分批计算后合并结果
内容的提问来源于stack exchange,提问作者user2205916
相关产品推荐
相关产品推荐

