直接用merge失败是因为pandas默认精确匹配,而数据存在拼写、缩写、空格、大小写等差异;需改用基于语义相似度的模糊匹配策略。

为什么直接用 merge 会失败?
两张表的列名或内容存在拼写差异、缩写、空格、大小写混用(比如 "Beijing" vs "BJ City"),pandas.merge 默认只做精确匹配,找不到键就全填 NaN。这不是数据问题,是匹配逻辑不适用——得换“语义相似”而非“字符相等”的思路。
fuzz.ratio() 和 fuzz.token_sort_ratio() 怎么选?
两者都返回 0–100 的整数,但行为差别很大:
-
fuzz.ratio("New York", "new york")→ 80(区分大小写+顺序敏感) -
fuzz.token_sort_ratio("New York", "new york")→ 100(先转小写、分词、排序再比) - 如果字段含冗余词(如
"Shanghai Tech University"vs"Tech Univ Shanghai"),优先用token_sort_ratio - 若顺序本身重要(如地址层级:
"Room 201, Bldg A"vs"Bldg A, Room 201"),可试partial_ratio或组合策略
怎么把模糊匹配结果变成可用的 merge?
不能直接丢给 pd.merge,得先生成「最可能的匹配对」。核心步骤是:对左表每行,在右表中找相似度最高的项,并设阈值过滤低置信结果:
from fuzzywuzzy import fuzz
import pandas as pd
def get_best_match(val, candidates, scorer=fuzz.token_sort_ratio, threshold=70):
scores = [(c, scorer(str(val), str(c))) for c in candidates]
best = max(scores, key=lambda x: x[1])
return best[0] if best[1] >= threshold else None
df1["match_key"] = df1["name_col"].apply(
lambda x: get_best_match(x, df2["company_name"].unique())
)
result = df1.merge(df2, left_on="match_key", right_on="company_name", how="left")
注意点:
立即学习“Python免费学习笔记(深入)”;
- 务必用
df2["xxx"].unique()缩减候选集,否则O(n×m)太慢 -
threshold别硬设 80——先抽样看分布,70是常见起点,但医疗/金融类名称可能需调到85+ - 如果右表有重复名,
merge会产生笛卡尔积,提前用drop_duplicates处理
中文匹配为什么效果差?需要额外处理吗?
fuzzywuzzy 原生按字符比,对中文基本等价于“字数相同且字序一致才高分”,"北京中关村" 和 "中关村 北京" 得分可能只有 40。必须预处理:
- 用
jieba分词后 join 成空格分隔字符串:"北京 中关村"vs"中关村 北京" - 去掉停用词(“市”“省”“有限公司”等),否则
"杭州阿里巴巴"和"杭州阿里巴巴有限公司"相似度被拉低 - 别依赖
fuzz.WRatio——它内部加权策略对中文不透明,实测不如手动分词+token_sort_ratio
真正难的不是算分,是定义“什么叫合理匹配”。比如 "腾讯" 和 "腾讯科技" 算不算?这得看业务规则,代码只能给你候选,拍板还得人来定。


















