【问题标题】:Why does fuzzywuzzy not consider character order为什么fuzzywuzzy不考虑字符顺序
【发布时间】:2017-06-01 05:24:12
【问题描述】:

考虑这个例子:

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

在上述情况下,对于给定字符串,account 排名高于 update,这让我的最终用户感到困惑。在这种情况下,由于列表顺序,account 恰好被任意放在前面,因为所有匹配项共享相同的分数。但是,我会想象 update 会获得更高的分数,这仅仅是因为字符 u 出现在字符串的前面。

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

【问题讨论】:

    标签: python fuzzy-search fuzzywuzzy


    【解决方案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) 是衡量两个字符串之间相似度的指标,我们将其称为源字符串 (s) 和目标字符串 (t)。距离是将 s 转换为 t 所需的删除、插入或替换的数量。

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

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

    【讨论】:

    • 感谢您的解释。不过我很好奇——这不是大多数模糊搜索的自然行为吗?例如,在 Sublime Text/Visual Studio Code 中使用 CMD + SHIFT + P 并键入 u 将突出显示命令中的 u 字符,但它总是首先显示以 u 开头的命令。
    • 我猜他们要么创建了自己的模糊匹配算法,要么只是使用了不同的库。 fuzzyset 开箱即用似乎做得很好,您可能想尝试一下。 (不要使用 pip 包,它已经过时了!下载 github repo 并轻松安装)
    【解决方案2】:

    在您的代码中:

    process.extract('u', choices)  
    

    您没有将 scorer 函数传递给 extract 方法。该方法将为您选择 4 个足球的最大比例。

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

    在您的情况下,原始字符串是u,目标字符串是account,update,query
    基本比例为account : 25update : 29query : 33
    部分比例均为90。
    并且token sort ratio和token set ratio都是85.5。
    所以每个字符串的最大比例是90。
    所以你得到了输出[('account', 90), ('update', 90), ('query', 90)]

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2019-09-30
        • 2017-11-01
        • 1970-01-01
        • 2018-05-14
        • 1970-01-01
        • 2019-10-07
        • 2012-06-04
        • 2017-04-26
        相关资源
        最近更新 更多