告别文本匹配烦恼:Fuzzywuzzy让相似字符串识别变得如此简单
你是否曾遇到过这样的问题:用户输入的"张三"和系统中的"张小三"其实是同一个人,却因为名字写法不同导致无法匹配?或者在处理大量文本数据时,需要找出那些拼写相近但不完全相同的条目?这些问题在数据清洗、用户输入处理、信息检索等场景中非常常见。Fuzzywuzzy就是解决这类问题的利器,它能轻松计算字符串之间的相似度,让你告别繁琐的手动比对。
读完本文,你将能够:
- 理解Fuzzywuzzy的基本原理和核心功能
- 掌握Fuzzywuzzy的安装和基本使用方法
- 学会在实际场景中应用Fuzzywuzzy解决文本匹配问题
- 了解Fuzzywuzzy的高级用法和性能优化技巧
Fuzzywuzzy简介
Fuzzywuzzy是一个Python库,专门用于计算字符串之间的相似度,也就是模糊字符串匹配(Fuzzy String Matching)。它基于Levenshtein距离(编辑距离)算法,能够快速准确地比较两个字符串的相似程度,并给出一个0到100之间的评分,分数越高表示相似度越高。
Fuzzywuzzy的核心功能模块主要集中在fuzzywuzzy/fuzz.py和fuzzywuzzy/process.py两个文件中。其中,fuzz.py提供了多种字符串相似度计算方法,而process.py则提供了从列表中查找最佳匹配项的功能。
该项目的当前版本为0.18.0,可以通过查看fuzzywuzzy/init.py文件获取版本信息。
安装Fuzzywuzzy
安装Fuzzywuzzy非常简单,只需要使用pip命令即可:
pip install fuzzywuzzy
此外,为了提高匹配速度,建议同时安装python-Levenshtein库:
pip install python-Levenshtein
如果不安装python-Levenshtein,Fuzzywuzzy会使用纯Python实现的SequenceMatcher,虽然功能相同,但速度会慢一些。这一点在fuzzywuzzy/fuzz.py的代码中可以看到:
try:
from .StringMatcher import StringMatcher as SequenceMatcher
except ImportError:
if platform.python_implementation() != "PyPy":
warnings.warn('Using slow pure-python SequenceMatcher. Install python-Levenshtein to remove this warning')
from difflib import SequenceMatcher
基本用法
字符串相似度计算
Fuzzywuzzy提供了多种计算字符串相似度的方法,主要在fuzzywuzzy/fuzz.py中实现。下面介绍几种常用的方法:
ratio方法
ratio方法是最基本的相似度计算方法,它直接计算两个字符串的编辑距离,并返回相似度评分。
from fuzzywuzzy import fuzz
s1 = "张三"
s2 = "张小三"
print(fuzz.ratio(s1, s2)) # 输出: 75
这个方法在fuzzywuzzy/fuzz.py中的实现如下:
def ratio(s1, s2):
s1, s2 = utils.make_type_consistent(s1, s2)
m = SequenceMatcher(None, s1, s2)
return utils.intr(100 * m.ratio())
partial_ratio方法
partial_ratio方法用于计算两个字符串中最相似的子串的相似度。当一个字符串是另一个字符串的子串,或者两个字符串有很大一部分重叠时,这个方法非常有用。
from fuzzywuzzy import fuzz
s1 = "张三"
s2 = "张小三"
print(fuzz.partial_ratio(s1, s2)) # 输出: 100
可以看到,对于"张三"和"张小三",partial_ratio给出了100分,因为"张三"是"张小三"的前两个字符。这个方法的实现逻辑在fuzzywuzzy/fuzz.py的partial_ratio函数中。
token_sort_ratio方法
token_sort_ratio方法首先将字符串分词,然后对分词结果进行排序,再计算相似度。这对于那些单词顺序不同但内容相同的字符串非常有用。
from fuzzywuzzy import fuzz
s1 = "张三 李四"
s2 = "李四 张三"
print(fuzz.ratio(s1, s2)) # 输出: 50
print(fuzz.token_sort_ratio(s1, s2)) # 输出: 100
可以看到,虽然ratio方法给出的分数较低,但token_sort_ratio方法正确识别出了两个字符串的内容相同,只是顺序不同。这个方法的实现逻辑在fuzzywuzzy/fuzz.py的_token_sort和token_sort_ratio函数中。
WRatio方法
WRatio方法是一种加权的相似度计算方法,它综合考虑了多种因素,包括部分匹配、令牌排序等,通常能给出更合理的结果。在大多数情况下,推荐使用WRatio方法。
from fuzzywuzzy import fuzz
s1 = "张三"
s2 = "张小三"
print(fuzz.WRatio(s1, s2)) # 输出: 80
WRatio方法的实现比较复杂,在fuzzywuzzy/fuzz.py中占据了较大篇幅。它的核心思想是综合多种相似度计算方法的结果,并根据字符串长度等因素进行加权处理,最终给出一个综合评分。
从列表中查找最佳匹配
除了计算两个字符串的相似度,Fuzzywuzzy还提供了从列表中查找与目标字符串最相似的元素的功能,这部分功能主要在fuzzywuzzy/process.py中实现。
extractOne方法
extractOne方法用于从列表中查找与目标字符串最相似的单个元素。
from fuzzywuzzy import process
choices = ["张三", "李四", "王五", "赵六"]
query = "张小三"
best_match = process.extractOne(query, choices)
print(best_match) # 输出: ('张三', 80)
这个结果表示,"张三"是与"张小三"最相似的字符串,相似度评分为80。extractOne方法的实现可以在fuzzywuzzy/process.py中找到:
def extractOne(query, choices, processor=default_processor, scorer=default_scorer, score_cutoff=0):
best_list = extractWithoutOrder(query, choices, processor, scorer, score_cutoff)
try:
return max(best_list, key=lambda i: i[1])
except ValueError:
return None
extract方法
extract方法用于从列表中查找与目标字符串最相似的多个元素,并按相似度排序。
from fuzzywuzzy import process
choices = ["张三", "李四", "王五", "赵六", "张大三", "张小三"]
query = "张三"
matches = process.extract(query, choices, limit=3)
print(matches) # 输出: [('张三', 100), ('张小三', 80), ('张大三', 75)]
这个结果表示,与"张三"最相似的三个字符串分别是"张三"(100分)、"张小三"(80分)和"张大三"(75分)。extract方法的实现也在fuzzywuzzy/process.py中。
高级用法
自定义处理器
Fuzzywuzzy允许用户自定义处理器(processor),用于在匹配之前对字符串进行预处理。默认的处理器是utils.full_process,它会对字符串进行大小写转换、去除标点符号等处理。如果需要自定义处理逻辑,可以传递一个函数作为processor参数。
例如,如果我们希望忽略字符串中的数字,可以定义这样一个处理器:
from fuzzywuzzy import process
def ignore_digits(s):
return ''.join([c for c in s if not c.isdigit()])
choices = ["张三1", "张三2", "李四", "王五"]
query = "张三"
matches = process.extract(query, choices, processor=ignore_digits)
print(matches) # 输出: [('张三1', 100), ('张三2', 100), ('李四', 0), ('王五', 0)]
在这个例子中,我们自定义的ignore_digits处理器会去除字符串中的数字,因此"张三1"和"张三2"在处理后都变成了"张三",与查询字符串完全匹配。
关于处理器的更多信息,可以查看fuzzywuzzy/process.py中extractWithoutOrder函数的相关代码。
自定义评分器
除了自定义处理器,Fuzzywuzzy还允许用户自定义评分器(scorer),也就是用于计算字符串相似度的函数。默认的评分器是fuzz.WRatio,我们也可以使用其他评分器,或者自定义自己的评分器。
例如,我们可以指定使用fuzz.token_sort_ratio作为评分器:
from fuzzywuzzy import process, fuzz
choices = ["张三 李四", "李四 张三", "王五 赵六"]
query = "李四 张三"
matches = process.extract(query, choices, scorer=fuzz.token_sort_ratio)
print(matches) # 输出: [('张三 李四', 100), ('李四 张三', 100), ('王五 赵六', 0)]
在这个例子中,由于使用了token_sort_ratio评分器,"张三 李四"和"李四 张三"被认为是完全相似的,都得到了100分。
关于评分器的更多信息,可以参考fuzzywuzzy/fuzz.py中的各种相似度计算函数。
去重功能
Fuzzywuzzy还提供了一个dedupe函数,用于对列表中的字符串进行去重,保留与其他字符串相似度较低的元素。这个功能在fuzzywuzzy/process.py中实现。
from fuzzywuzzy import process
contains_dupes = ["张三", "张小三", "张三三", "李四", "李四五"]
deduped = process.dedupe(contains_dupes, threshold=70)
print(deduped) # 输出: ['张三', '李四']
在这个例子中,threshold参数设置为70,表示相似度高于70的字符串会被认为是重复的。因此,"张三"、"张小三"和"张三三"被视为重复,只保留了"张三";"李四"和"李四五"被视为重复,只保留了"李四"。
关于dedupe函数的更多信息,可以查看fuzzywuzzy/process.py中的相关代码。
实际应用场景
数据清洗
在数据处理中,经常会遇到一些格式不统一但内容相似的数据,例如不同写法的姓名、地址等。使用Fuzzywuzzy可以轻松识别这些相似数据,进行统一处理。
例如,在一个用户数据库中,可能存在"张三"、"张小三"、"张三先生"等不同写法,我们可以使用Fuzzywuzzy将这些记录合并:
from fuzzywuzzy import process
users = ["张三", "张小三", "张三先生", "李四", "李四同学"]
unique_users = process.dedupe(users, threshold=60)
print(unique_users) # 输出: ['张三先生', '李四同学']
搜索引擎优化
在搜索引擎中,用户输入的查询词可能存在拼写错误,或者与目标内容的关键词不完全匹配。使用Fuzzywuzzy可以实现模糊搜索,提高搜索结果的相关性。
例如,一个简单的模糊搜索实现:
from fuzzywuzzy import process
def fuzzy_search(query, documents, top_n=3):
scores = []
for doc in documents:
score = process.extractOne(query, [doc], scorer=fuzz.WRatio)[1]
scores.append((doc, score))
scores.sort(key=lambda x: x[1], reverse=True)
return scores[:top_n]
documents = [
"Fuzzywuzzy是一个Python模糊字符串匹配库",
"Python字符串处理技巧",
"Levenshtein距离算法介绍",
"数据清洗常用工具"
]
results = fuzzy_search("fuzzy匹配", documents)
for doc, score in results:
print(f"{score}: {doc}")
这个简单的模糊搜索引擎会返回与"fuzzy匹配"最相关的文档。
性能优化
对于大规模数据的模糊匹配,Fuzzywuzzy的性能可能会成为瓶颈。以下是一些性能优化的建议:
- 安装python-Levenshtein:如前所述,这可以显著提高匹配速度。
- 使用适当的评分器:不同的评分器性能不同,例如ratio方法比WRatio方法快,但准确率可能稍低。根据实际需求选择合适的评分器。
- 减少不必要的计算:如果只需要查找最佳匹配,可以使用extractOne方法,而不是extract方法。
- 批量处理:对于大量数据,可以考虑批量处理,或者使用多线程/多进程并行处理。
总结
Fuzzywuzzy是一个功能强大且易用的Python模糊字符串匹配库,它基于Levenshtein距离算法,提供了多种字符串相似度计算方法和从列表中查找最佳匹配的功能。通过本文的介绍,我们了解了Fuzzywuzzy的基本用法、高级特性和实际应用场景。
主要功能模块包括:
- fuzzywuzzy/fuzz.py:提供多种字符串相似度计算方法。
- fuzzywuzzy/process.py:提供从列表中查找最佳匹配和去重功能。
无论是数据清洗、搜索引擎优化,还是用户输入纠错,Fuzzywuzzy都能发挥重要作用。希望本文能帮助你更好地理解和使用Fuzzywuzzy,解决实际工作中的字符串匹配问题。
最后,需要注意的是,Fuzzywuzzy项目已经更名为TheFuzz,并迁移到了新的仓库。如果你在使用过程中遇到问题,可以参考新仓库的文档和代码。这一点在项目的README.md中已有说明:
This project has been renamed and moved to https://github.com/seatgeek/thefuzz
TheFuzz version 0.19.0 correlates with this project's 0.18.0 version with `thefuzz` replacing all instances of this project's name.
PRs and issues here will need to be resubmitted to TheFuzz
参考资料
- Fuzzywuzzy源代码:gh_mirrors/fu/fuzzywuzzy
- Fuzzywuzzy核心相似度计算模块:fuzzywuzzy/fuzz.py
- Fuzzywuzzy匹配和去重模块:fuzzywuzzy/process.py
- 项目说明文档:README.md
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



