2017-06-01 66 views
1

考虑这个例子:为什么fuzzywuzzy不考虑字符顺序

>> from fuzzywuzzy import process 
>> choices = ['account', 'update', 'query'] 
>> process.extract('u', choices) 
[('account', 90), ('update', 90), ('query', 90)] 

在上述情况下,它混​​淆了我的最终用户是帐户排名上面更新对于给定的字符串。在这种情况下,帐户由于列表顺序而恰好被置于前面,因为所有的比赛都有相同的得分。不过,我会想象更新会有更高的分数,只是因为字符串中出现字符u

这是一个概念错误还是我没有在这里使用正确的得分手?

回答

1

首先你使用的是一个“坏”的得分手。根据你的分数你可能使用difflib。您应该切换到基于python-Levenshtein的实施。这可以通过参数scorer完成。

from fuzzywuzzy import process 
from fuzzywuzzy import fuzz 

def MyScorer(s1, s2): 
    fratio = fuzz.ratio(s1, s2) 
    fratio -= (s2.find(s1)*5) 
    return fratio 

choices = ['account', 'update', 'query'] 
dex = process.extract('u', choices, scorer=fuzz.token_sort_ratio) 
mex = process.extract('u', choices, scorer=MyScorer) 
print("Default Scorer:", dex) 
print("MyScorer:", mex) 

现在输出

[('query', 33), ('update', 29), ('account', 25)]

哪个更好,但Levenshtein并没有真正关心的位置,

Levenshtein距离(LD)是衡量两个字符串之间的相似性,我们将其称为源字符串和目标字符串(t)。距离是将s转换为t所需的删除,插入或替换的数量。

这就是为什么我添加了MyScorer()的定义,您可以在其中实现您自己的算法,将该位置考虑在内。我还添加了一个考虑位置的实现示例(但我没有真正设计这些算法的经验,所以不要指望这个算法是完美的或者甚至是可用的)。无论如何,MyScorer的输出是:

[('update', 29), ('query', 28), ('account', 5)]

+0

感谢您的解释。我很好奇 - 这不是大多数模糊搜索的自然行为吗?例如,在Sublime Text/Visual Studio Code中使用** CMD + SHIFT + P **并键入* u *将突出显示命令中的* u *字符,但它总是以* u *开头的命令显示。 –

+0

我想他们要么创建了自己的模糊匹配算法,要么他们只是使用了不同的库。 [fuzzyset](https://github.com/axiak/fuzzyset)开箱即可出色完成工作,你可能想尝试一下。 (不要使用pip软件包,它已经过时了!下载github软件仓库和easy_install软件) – Skynet

0

“process.extract”在选择的列表或字典中查找最佳匹配,返回包含匹配和它的分数的元组列表。它不依赖于列表或字典中选项的“位置”。

0

在您的代码:

process.extract('u', choices) 

你不及格的得分手函数提取方法。该方法将为您选择4个足球的最大比例。

  • base_ratio:Levenshtein距离的两个字符串。
  • partial_ratio:最相似子串的比例。
  • token_sort_ratio:在比较之前测量序列的相似性,对令牌进行排序。
  • token_set_ratio:查找每个字符串中的所有字母数字标记。

在你的情况,原点字符串是u,和目标串accountupdatequery
基本比例是account : 25,update : 29,query : 33
部分比例均为90.
并且令牌分类比例和令牌设置比率均为85.5。
所以每个字符串的最大比率是90.
所以你得到输出[('account', 90), ('update', 90), ('query', 90)]

相关问题