何时使用哪个模糊函数来比较 2 个字符串

Posted

技术标签:

【中文标题】何时使用哪个模糊函数来比较 2 个字符串【英文标题】:When to use which fuzz function to compare 2 strings 【发布时间】:2015-10-26 16:55:52 【问题描述】:

我正在学习 Python 中的fuzzywuzzy

我了解fuzz.ratiofuzz.partial_ratiofuzz.token_sort_ratiofuzz.token_set_ratio 的概念。我的问题是什么时候使用哪个功能?

我是否首先检查 2 个字符串的长度,如果不相似,则说规则 fuzz.partial_ratio? 如果 2 个字符串的长度相似,我将使用 fuzz.token_sort_ratio? 我应该一直使用fuzz.token_set_ratio吗?

有人知道 SeatGeek 使用什么标准吗?

我正在尝试建立一个房地产网站,想使用fuzzywuzzy 来比较地址。

【问题讨论】:

【参考方案1】:

很好的问题。

我是 SeatGeek 的工程师,所以我想我可以在这里提供帮助。我们有一个很棒的 blog post 很好地解释了这些差异,但我可以总结并提供一些关于我们如何使用不同类型的见解。

概述

在后台,这四种方法中的每一种都会计算两个输入字符串中某些标记排序之间的编辑距离。这是使用difflib.ratio 函数which will 完成的:

返回序列相似性的度量(在 [0,1] 中浮动)。

其中 T 是两个序列中元素的总数,M 是 匹配的数量,这是 2.0*M / T。请注意,如果 序列是相同的,如果它们没有共同点,则为 0。

四个fuzzywuzzy 方法在输入字符串的不同组合上调用difflib.ratio

fuzz.ratio

简单。只需在两个输入字符串 (code) 上调用 difflib.ratio

fuzz.ratio("NEW YORK METS", "NEW YORK MEATS")
> 96

fuzz.partial_ratio

尝试更好地解释部分字符串匹配。使用最短字符串(长度 n)对较大字符串的所有 n 长度子字符串调用 ratio,并返回最高分(code)。

请注意,“YANKEES”是最短的字符串(长度为 7),我们将“YANKEES”与“NEW YORK YANKEES”的所有长度为 7 的子字符串(包括检查“YANKEES”,a 100% 匹配):

fuzz.ratio("YANKEES", "NEW YORK YANKEES")
> 60
fuzz.partial_ratio("YANKEES", "NEW YORK YANKEES")
> 100

fuzz.token_sort_ratio

尝试无序地解释类似的字符串。在对每个字符串 (code) 中的标记进行排序后,在两个字符串上调用 ratio。请注意,fuzz.ratiofuzz.partial_ratio 都失败了,但是一旦你对令牌进行排序,它就会 100% 匹配:

fuzz.ratio("New York Mets vs Atlanta Braves", "Atlanta Braves vs New York Mets")
> 45
fuzz.partial_ratio("New York Mets vs Atlanta Braves", "Atlanta Braves vs New York Mets")
> 45
fuzz.token_sort_ratio("New York Mets vs Atlanta Braves", "Atlanta Braves vs New York Mets")
> 100

fuzz.token_set_ratio

尝试排除字符串中的差异。调用三个特定子字符串集的比率并返回最大值 (code):

    仅交集和与字符串 1 其余部分的交集 仅交集和与字符串 2 其余部分的交集 余数为 1 和余数为 2 的交点

请注意,通过拆分两个字符串的交集和余数,我们可以同时考虑两个字符串的相似和不同之处:

fuzz.ratio("mariners vs angels", "los angeles angels of anaheim at seattle mariners")
> 36
fuzz.partial_ratio("mariners vs angels", "los angeles angels of anaheim at seattle mariners")
> 61
fuzz.token_sort_ratio("mariners vs angels", "los angeles angels of anaheim at seattle mariners")
> 51
fuzz.token_set_ratio("mariners vs angels", "los angeles angels of anaheim at seattle mariners")
> 91

应用

这就是魔法发生的地方。在 SeatGeek,我们基本上为每个数据点(地点、事件名称等)创建了一个包含每个比率的向量分数,并使用它来为特定于我们问题领域的相似性的程序决策提供信息。

话虽如此,说实话听起来 FuzzyWuzzy 对您的用例没有用处。确定两个地址是否相似将非常糟糕。考虑 SeatGeek HQ 的两个可能地址:“235 Park Ave Floor 12”和“235 Park Ave S. Floor 12”:

fuzz.ratio("235 Park Ave Floor 12", "235 Park Ave S. Floor 12")
> 93
fuzz.partial_ratio("235 Park Ave Floor 12", "235 Park Ave S. Floor 12")
> 85
fuzz.token_sort_ratio("235 Park Ave Floor 12", "235 Park Ave S. Floor 12")
> 95
fuzz.token_set_ratio("235 Park Ave Floor 12", "235 Park Ave S. Floor 12")
> 100

FuzzyWuzzy 为这些字符串提供了很高的匹配分数,但其中一个地址是我们在联合广场附近的实际办公室,而另一个地址位于 Grand Central 的另一侧。

对于您的问题,您最好使用Google Geocoding API。

【讨论】:

嗨瑞克,感谢您愿意提供帮助。我明白了使用 Google Geocoding API 的意义,我会花更多时间在上面。自从我学到了这么远的学习位Geek,我想更好地了解魔术发生的“应用程序”。 seatGeek 系统是否将即将举行的活动、场地、表演者保存在单独的列表(在 python 中)/数组中?因此,当我输入巨人时,它会检查这些列表,然后执行所有 4 个比率函数调用,它会排除那些低分的项目,将那些高分项目保留在下拉框中。您会预设低分和高分阈值吗? 我们为每个活动、场地和表演者创建一个规范来源,并将新输入与规范来源进行比较,以便将它们配对,以便当用户开始搜索“巨人”时,我们会搜索规范来源,而不是我们摄取的所有潜在输入。我希望这能让它更清楚。 如果我理解正确,您可以将这些活动、表演者和场地标准化和规范化。您找到的任何来源都将映射到这些规范列表,除非您在规范列表中找不到很好的匹配项,否则您将创建一个新条目并存储它们。所以当我输入巨人时,seatgeek 只是搜索这些规范列表。如果它太敏感而无法分享,我不会感到难过,我不是想在亚洲建立一个seatgeek,只是出于兴趣。 :) 非常感谢你的洞察力,和你聊天我学到了很多东西。我相信这个模糊的概念总有一天会帮助我的发展。 我很惊讶你没有训练 NLP 模型,看起来它会很容易并且性能更好。 你能用第一个例子向我解释一下 2.0*M / T 是如何应用的吗?我需要了解 difflib 是如何工作的【参考方案2】:

截至 2017 年 6 月,fuzzywuzzy 还包括一些其他比较功能。以下是已接受答案中遗漏的概述(取自source code):

fuzz.partial_token_sort_ratio

token_sort_ratio 中的算法相同,但不是在对标记进行排序后应用ratio,而是使用partial_ratio

fuzz.token_sort_ratio("New York Mets vs Braves", "Atlanta Braves vs New York Mets")
> 85
fuzz.partial_token_sort_ratio("New York Mets vs Braves", "Atlanta Braves vs New York Mets")
> 100    
fuzz.token_sort_ratio("React.js framework", "React.js")
> 62
fuzz.partial_token_sort_ratio("React.js framework", "React.js")
> 100

fuzz.partial_token_set_ratio

token_set_ratio 中的算法相同,但不是将ratio 应用于令牌集,而是使用partial_ratio

fuzz.token_set_ratio("New York Mets vs Braves", "Atlanta vs New York Mets")
> 82
fuzz.partial_token_set_ratio("New York Mets vs Braves", "Atlanta vs New York Mets")
> 100    
fuzz.token_set_ratio("React.js framework", "Reactjs")
> 40
fuzz.partial_token_set_ratio("React.js framework", "Reactjs")
> 71   

fuzz.QRatio,fuzz.UQRatio

只是对fuzz.ratio 进行了一些验证和短路的包装,为了完整起见,在此处包含这些内容。 UQRatioQRatio 的 unicode 版本。

fuzz.WRatio

尝试加权(名称代表“加权比”)来自不同算法的结果 计算“最佳”分数。 来自源代码的说明:

1. Take the ratio of the two processed strings (fuzz.ratio)
2. Run checks to compare the length of the strings
    * If one of the strings is more than 1.5 times as long as the other
      use partial_ratio comparisons - scale partial results by 0.9
      (this makes sure only full results can return 100)
    * If one of the strings is over 8 times as long as the other
      instead scale by 0.6
3. Run the other ratio functions
    * if using partial ratio functions call partial_ratio,
      partial_token_sort_ratio and partial_token_set_ratio
      scale all of these by the ratio based on length
    * otherwise call token_sort_ratio and token_set_ratio
    * all token based comparisons are scaled by 0.95
      (on top of any partial scalars)
4. Take the highest value from these results
   round it and return it as an integer.

fuzz.UWRatio

WRatio 的 Unicode 版本。

【讨论】:

以上是关于何时使用哪个模糊函数来比较 2 个字符串的主要内容,如果未能解决你的问题,请参考以下文章

模糊查询

第十章模糊函数和聚合函数

python模糊匹配库能否定制匹配关系

ORACLE INSTR函数及模糊查询

字符串模糊匹配

java连接数据库的模糊查询