python字符串模糊匹配 - FuzzyWuzzy

简介

字符串模糊匹配在很多问题中有实际价值。比如NER或任何词条关联问题,将不规范的词条与标准词条进行链接匹配。在数据量大或包含关系复杂时,使用优秀的工具包可极大提升效率。

FuzzyWuzzy 既是这样一个可进行字符串模糊匹配的python包,根据Levenshtein Distance(也被称为Edit Distance,指两个字符串,有一个转换成另一个所需要的最少操作次数)计算字符串之间的差异。这在序列比对中也是很常用的算法。编辑距离越小,两个字符串相似度越高。

FuzzyWuzzy已更新到0.18.0 版本,目前已更名为TheFuzz,对应0.19.0版本。而目前是使用更多的则是RapidFuzz,运行速度更快,参见另一篇介绍。

安装:pip install fuzzywuzzy 或 pip install thefuzz

FuzzyWuzzy使用

主要有2种用法:

  • 比较计算两个字符串的相似度,返回值为0-100,表示相似度比率,使用各类ratio方法;
  • 在候选列表中查询与目标字符串最相似的字符串,使用process;

适用的模糊匹配关系如下:

  • 完全匹配;
  • 子字符串匹配;
  • 不考虑子词顺序的匹配;
  • 不考虑子词顺序和个数的匹配;

其中前两种方法基于字符串,大小写敏感。后两种方法基于token,大小写不敏感且忽略标点符号。

简单完全匹配(Simple Ratio)

直接使用Levenshtein.ratio, 计算公式:r = (sum - dist) / sum。式中idist是类编辑距离,即编辑距离中的替换需要操作两次,sum是字符串长度和。

>>> from fuzzywuzzy import fuzz,process
>>> fuzz.ratio("this is a test", "this is a test!")
97
>>> fuzz.ratio("这是测试", "这是测验") # (8-2)/8
75

子字符串匹配(Partial Ratio)

先找到最长相似子字符串,再计算其与较短字符串的相似度。返回最相似的子字符串的相似度。

>>> fuzz.partial_ratio("this is a test", "this is a test!")
100
>>> fuzz.partial_ratio("这是测试示例", "这是测验")
75

不考虑词顺序的匹配(Token Sort Ratio)

先调用 process_and_sort(s1, force_ascii, full_process=full_process),将字符串按空格切分,对token按字母顺序排序后合并为新的字符串,再进行相似度计算。

  • force_ascii:bool,表示是否转换为ascii码后再进行full_process处理;
  • full_process:bool,表示是否去除非字母,非数字(空格保留);否则不进行处理;

该方法要求字符串由多个词组成,如果是中文,需要提前进行分词。

>>> fuzz.ratio("fuzzy wuzzy was a bear", "wuzzy fuzzy was a bear")
91
>>> fuzz.token_sort_ratio("fuzzy wuzzy was a bear", "wuzzy fuzzy was a bear")
100

该方法默认partial=False,比较全长字符串,另有partial_token_sort_ratio方法可用,字符串处理后可返回最大子串相似度。

去重子集匹配(Token Set Ratio)

与token_sort_ratio类似,不考虑子词顺序,并且不考虑token数目。先对两个字符串s1,s2根据full_process取值进行full_process处理,之后对token去重,获取交集inters和差集(diff1to2,diff2to1),并排序。然后构建(inters_sort,inters_sort+diff1to2_sort),(inters_sort,inters_sort+diff2to1_sort),(diff1to2_sort,diff2to1_sort)3个比较集合,返回相似度最大值。

>>> fuzz.token_sort_ratio("fuzzy was a bear", "fuzzy fuzzy was a bear")
84
>>> fuzz.token_set_ratio("fuzzy was a bear", "fuzzy fuzzy was a bear")
100

该方法默认partial=False,比较全长字符串,另有partial_token_set_ratio方法可用,字符串处理后可返回最大子串相似度。

QRatio / WRatio

QRatio(Quick)似乎是为了在其他方法调用时,减少一些重复的字符串操作。
​WRatio(Weighted)使用了不同的算法,在使用ratio/partial_ratio获得结果后,根据序列长度进行相似度校正。

  • 使用ratio时,如果一个字符串的长度是另一个的1.5倍,使用partial_ratio,并将结果乘以权重0.9。如果长度是另一个的8倍,权重设为0.6。
  • 如果使用了partial_ratio,partial_token_sort_ratio 或partial_token_set_ratio,都要根据长度加权处理,权重设为0.95。

Process

从候选列表中,返回与目标字符串最相似的一个或指定个数,可在大规模列表中直接搜索。
默认ratio计算为fuzz.WRatio,可在scorer参数指定相似度计算方法。

>>> choices = ["Atlanta Falcons", "New York Jets", "New York Giants", "Dallas Cowboys"]
>>> process.extract("new york jets", choices, limit=2)
[('New York Jets', 100), ('New York Giants', 78)]
>>> process.extractOne("cowboys", choices)
("Dallas Cowboys", 90)
# 指定 scorer
>>> process.extractOne("System of a down - Hypnotize", songs, scorer=fuzz.token_sort_ratio)

参数:

  • score_cutoff:设置相似度阈值;
  • scorer:指定相似度计算方法;
  • limit:设置返回个数;

总结

FuzzyWuzzy提供了快速方便的字符串模糊匹配和搜索方法。一般更有用的是process模块,提供封装好的函数,可以指定fuzz模块中的不同相似度计算方法,可在大规模候选集合中找到与查询字符串最相似的结果。
字符串模糊匹配的核心是两个字符串的相似度计算,详细可参考 python-Levenshtein 库的原理和使用。

参考

FuzzyWuzzy:https://github.com/seatgeek/fuzzywuzzy
TheFuzz:https://github.com/seatgeek/thefuzz
https://medium.com/@laxmi17sarki/string-matching-using-fuzzywuzzy-24be9e85c88d

你可能感兴趣的:(python,NLP,python,开发语言)