为什么fuzzywuzzy不考虑字符顺序
Why does fuzzywuzzy not consider character order
考虑这个例子:
>> from fuzzywuzzy import process
>> choices = ['account', 'update', 'query']
>> process.extract('u', choices)
[('account', 90), ('update', 90), ('query', 90)]
在上述情况下,对于给定的字符串,account 的排名高于 update,这让我的最终用户感到困惑。在这种情况下,account 由于列表顺序而恰好被任意放在前面,因为所有匹配项都共享相同的分数。但是,我本以为 update 会获得更高的分数,仅仅是因为字符 u 出现在字符串的前面。
这是概念上的错误还是我没有使用正确的得分手?
"process.extract" 在选择列表或字典中找到最佳匹配,return 包含匹配及其分数的元组列表。它不依赖于列表或字典中的 "Position" 个选项。
首先,您使用的是 "bad" 记分器。根据您的分数,您可能正在使用 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 distance (LD) is a measure of the similarity between two strings, which we will refer to as the source string (s) and the target string (t). The distance is the number of deletions, insertions, or substitutions required to transform s into t.
这就是为什么我添加了 MyScorer()
的定义,您可以在其中实施您自己的算法,该算法将位置考虑在内。我还添加了一个考虑位置的实现示例(但我在设计此类算法方面并没有真正的经验,所以不要指望这个算法是完美的甚至可用的)。不管怎样,MyScorer 的输出是:
[('update', 29), ('query', 28), ('account', 5)]
在您的代码中:
process.extract('u', choices)
您没有将计分器函数传递给提取方法。该方法将为您选择 4 个足球的最大比例。
- base_ratio : The Levenshtein Distance of two string.
- partial_ratio : The ratio of most similar substring.
- token_sort_ratio : Measure of the sequences' similarity sorting the token before comparing.
- token_set_ratio : Find all alphanumeric tokens in each string.
在您的例子中,原始字符串是 u
,目标字符串是 account
、update
、query
.
基本比例为account : 25
、update : 29
、query : 33
.
分率都是90.
并且token sort ratio和token set ratio都是85.5.
所以每个字符串的最大比例是90.
所以你得到输出 [('account', 90), ('update', 90), ('query', 90)]
.
考虑这个例子:
>> from fuzzywuzzy import process
>> choices = ['account', 'update', 'query']
>> process.extract('u', choices)
[('account', 90), ('update', 90), ('query', 90)]
在上述情况下,对于给定的字符串,account 的排名高于 update,这让我的最终用户感到困惑。在这种情况下,account 由于列表顺序而恰好被任意放在前面,因为所有匹配项都共享相同的分数。但是,我本以为 update 会获得更高的分数,仅仅是因为字符 u 出现在字符串的前面。
这是概念上的错误还是我没有使用正确的得分手?
"process.extract" 在选择列表或字典中找到最佳匹配,return 包含匹配及其分数的元组列表。它不依赖于列表或字典中的 "Position" 个选项。
首先,您使用的是 "bad" 记分器。根据您的分数,您可能正在使用 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 distance (LD) is a measure of the similarity between two strings, which we will refer to as the source string (s) and the target string (t). The distance is the number of deletions, insertions, or substitutions required to transform s into t.
这就是为什么我添加了 MyScorer()
的定义,您可以在其中实施您自己的算法,该算法将位置考虑在内。我还添加了一个考虑位置的实现示例(但我在设计此类算法方面并没有真正的经验,所以不要指望这个算法是完美的甚至可用的)。不管怎样,MyScorer 的输出是:
[('update', 29), ('query', 28), ('account', 5)]
在您的代码中:
process.extract('u', choices)
您没有将计分器函数传递给提取方法。该方法将为您选择 4 个足球的最大比例。
- base_ratio : The Levenshtein Distance of two string.
- partial_ratio : The ratio of most similar substring.
- token_sort_ratio : Measure of the sequences' similarity sorting the token before comparing.
- token_set_ratio : Find all alphanumeric tokens in each string.
在您的例子中,原始字符串是 u
,目标字符串是 account
、update
、query
.
基本比例为account : 25
、update : 29
、query : 33
.
分率都是90.
并且token sort ratio和token set ratio都是85.5.
所以每个字符串的最大比例是90.
所以你得到输出 [('account', 90), ('update', 90), ('query', 90)]
.