Fuzzywuzzy为何对完全相同的术语未返回100%相似度?
解决Fuzzywuzzy匹配相似度不符合预期的问题
先纠正代码中的致命错误
你的代码里有个关键错误:process.extract返回的每个匹配结果是**(匹配字符串, 相似度分数, 原列表索引)**,但你取了ratio[0][2](索引值)作为相似度,这完全不是真正的分数,这是导致你看到结果异常的直接原因!应该改成ratio[0][1]来获取相似度分数。
其他可能的原因及解决方案
1. 字符串存在隐藏格式差异
即使肉眼看起来相同的字符串,可能存在前后空格、全角/半角符号、不可见控制字符(换行、制表符)等差异,导致匹配分数异常。
解决方法:先对字符串做标准化清理:
def clean_string(s): if pd.isna(s): return "" # 去除前后空格、转小写、替换全角空格为半角、移除特殊符号(按需调整规则) return s.strip().lower().replace(' ', ' ').replace('[^a-zA-Z0-9\u4e00-\u9fa5]', '', regex=True) # 应用到两个数据框的名称列 df1['NAME_CLEAN'] = df1['NAME_LIST1'].apply(clean_string) df2['NAME_CLEAN'] = df2['NAME_LIST2'].apply(clean_string)
2. 默认匹配算法不适用你的场景
Fuzzywuzzy的process.extract默认使用WRatio算法,它是多种匹配逻辑的加权组合,在某些场景下(比如需要严格完全匹配),不如单一精准算法合适。
根据你的需求选择对应的匹配算法(通过scorer参数指定):
fuzz.ratio:严格逐字符比对,完全相同的字符串会返回100分,适合需要精确匹配的场景。fuzz.token_set_ratio:忽略单词顺序、重复项,适合短语类匹配(比如"苹果派"和"派苹果"会得到高分)。fuzz.partial_ratio:适合短字符串匹配长字符串的场景(比如"苹果"和"苹果派"会得到高分)。
修改后的匹配代码(结合清理后的字符串):
from fuzzywuzzy import process, fuzz NAME_MATCH = [] similarity = [] # 使用fuzz.ratio做严格匹配,也可根据需求替换其他scorer for i in df2.NAME_CLEAN: match_result = process.extract(i, df1.NAME_CLEAN, limit=1, scorer=fuzz.ratio) NAME_MATCH.append(match_result[0][0]) similarity.append(match_result[0][1]) # 正确获取相似度分数 df2['NAME_MATCH'] = NAME_MATCH df2['similarity'] = similarity
3. 验证字符串差异(排查疑难情况)
如果清理后还是有问题,可以打印字符串的原始字符编码,检查是否有隐藏字符:
# 取疑似相同的两个字符串 s1 = df1['NAME_LIST1'].iloc[0] s2 = df2['NAME_LIST2'].iloc[0] # 打印每个字符的Unicode编码 print([ord(c) for c in s1]) print([ord(c) for c in s2])
对比编码列表,就能发现是否有肉眼不可见的差异。
替代模糊匹配方案推荐
如果Fuzzywuzzy的效果仍不理想,可以尝试这些工具:
rapidfuzz:Fuzzywuzzy的优化复刻版,速度提升10-100倍,API完全兼容,适合大数据量匹配。difflib:Python标准库,适合简单的字符串相似度比对,无需额外安装。spaCy:结合NLP实体识别的专业匹配工具,适合名称、术语类的精准匹配。
内容的提问来源于stack exchange,提问作者smartini
相关产品推荐
相关产品推荐

