【问题标题】:Percentage rank of matches using Levenshtein Distance matching使用 Levenshtein 距离匹配的匹配百分比排名
【发布时间】:2012-05-11 10:29:12
【问题描述】:

我正在尝试使用 Levenshtein 距离算法将单个搜索词与可能匹配的字典进行匹配。该算法返回一个距离,表示为将搜索字符串转换为匹配字符串所需的操作数。 我想在排名前“N”(比如 10 个)匹配的百分比列表中显示结果。

由于搜索字符串可以比单个字典字符串更长或更短,将距离表示为百分比的适当逻辑是什么,这将定性地反映每个结果与查询字符串的“百分比”有多接近, 100% 表示完全匹配。

我考虑了以下选项:

Q = query string
M = matched string
PM = Percentage Match
Option 1. PMi = (1 - Lev_distance(Q, Mi)/Strlen(Q)) * 100
Option 2. PMi = (1 - Lev_distance(Q, Mi)/max(Strlen(Q), strlen(Mi))) * 100

如果距离大于搜索字符串长度(匹配字符串很长),选项 1 可能会出现负百分比。例如查询“ABC”与“ABC Corp.”匹配。会导致负匹配百分比。

选项 2 似乎没有在一组 Mi 中给出一致的百分比,因为每次计算都可能使用不同的分母,因此得到的百分比值不会被标准化。

我能想到的唯一其他方法是放弃 lev_distance 与任一字符串长度的比较,而是将前“N”个匹配的比较距离表示为反向百分位数排名(100-percentile-rank)。

有什么想法吗?有更好的方法吗?我一定遗漏了一些东西,因为 Levenshtein 距离可能是最常见的模糊匹配算法,这一定是一个非常常见的问题。

【问题讨论】:

  • 你的第一个选项怎么样,但是当结果为负时,然后简单地返回 0? PS:我在这里也发布了问题math.stackexchange.com/questions/1776860/…
  • 我不明白 Option2 有什么问题,因为我已经实现了与您在其上描述的完全相同的逻辑并且似乎可以正常工作。你能解释清楚吗?

标签: distance percentage ranking levenshtein-distance


【解决方案1】:
(1 - (levNum / Math.max(s.length,t.length) ) ) *100

应该是正确的

【讨论】:

  • 最初的问题已经将此解决方案作为“选项2”。他正在寻找解决问题的替代方案。
【解决方案2】:

这本质上是我的问题中提到的选项 2。但是,让我演示一下这种方法的一个问题。

Q = "ABC Corp" (len = 8)
M1 = "ABC"
M2 = "ABC Corporati"
M3 = "ABC Corp"

我选择了 M1 和 M2,使得它们的 Lev 距离相同(每个 5)。使用选项 2,匹配百分比将是

M1 = (1 - 5/8)*100  = 37.5%
M2 = (1 - 5/13)*100 = 61.5%
M3 = 100%

正如您所看到的,如果我按该顺序显示比赛,M1 和 M2 之间的排名差异很大,即使它们具有完全相同的 lev 距离。你看到问题了吗?

【讨论】:

  • 一段时间后,我想这是正确的方法。假设你有很短的字符串,其 LevDisstance 为 5。假设你有很长的字符串,其 LevDist 也是 5。那么说最短的字符串比更长的字符串更不相似是正确的。
  • Tbh,我认为那里没有问题,因为正如@Wakan Tanka 所说,与较长字符串的相同距离意味着它们之间匹配的字符更多。因此,没有问题,Option2 是一个有效的选项。
【解决方案3】:

我解决这个问题的方法是计算最大允许操作,这就是 Levenshtein 距离。我使用的公式是:

percent = 0.75; // at least 75% of string must match
maxOperationsFirst = s1.length() - s1.length() * percent;
maxOperationsSecond = s2.length() - s2.length() * percent;
maxOperations = round(min(maxOperationsFirst, maxOperationsSecond));

它计算每个字符串的最大操作数,我相信这个计算很容易理解。我使用两个结果的最小值并将其四舍五入到最接近的整数。您可以跳过这部分并仅使用任一字符串中的最大操作值,这实际上取决于您的数据。

获得最大操作数后,您可以将其与 levenshtein 结果进行比较,并确定该字符串是否可以接受。通过这种方式,您可以使用任何扩展的 levenshtein 方法,例如 Damerau–Levenshtein distance,它会计算拼写错误,e.g. test -> tset,仅作为 1 次操作,在检查经常出现拼写错误的用户输入时非常有用。

我希望这可以帮助您了解如何解决此问题。

【讨论】:

    【解决方案4】:

    我遇到了类似的问题,这个帖子帮助我找到了解决方案。希望它也可以帮助其他人。

    int levDis = Lev_distance(Q, Mi)
    int bigger = max(strlen(Q), strlen(Mi))
    double pct = (bigger - levDis) / bigger
    

    如果两个字符串完全相同,则返回 100%,如果完全不同,则返回 0%。

    (对不起,如果我的英语不是那么好)

    【讨论】:

    • 这是不正确的,因为它为 ("ABC Corp", "ABC")("ABC Corp", "ABC Corporati") 提供了不同的结果
    【解决方案5】:

    这个呢:

    100 - ( ((2*Lev_distance(Q, Mi)) / (Q.length + Mi.length)) * 100 )
    

    它在(Q, M1)(Q,M2) 上给出相同的距离

    【讨论】:

      【解决方案6】:

      levenshtein 距离的最大数量是[l1, l2].max。我认为这是真的。但我们不应该除此之外。

      gem install levenshtein diff-lcs
      
      Diff::LCS.lcs "abc", "qwer"
      => []
      Levenshtein.distance("abc", "qwer").to_f / [3, 4].max
      => 1.0
      
      Diff::LCS.lcs "abc", "cdef"
      => ["c"]
      Levenshtein.distance("abc", "cdef").to_f / [3, 4].max
      => 1.0
      
      Diff::LCS.lcs "1234", "34567890"
      => ["3", "4"]
      Levenshtein.distance("1234", "34567890").to_f / [4, 8].max
      => 1.0
      

      Levenshtein 看起来不像以 百分比 比较字符串的可靠方法。我不想将相似的字符串视为100% 不同

      我可以建议只分析每个序列和 LCS 之间的差异。

      def get_similarity(sequence_1, sequence_2)
        lcs_length = Diff::LCS::Internals.lcs(sequence_1, sequence_2).compact.length
        lcs_length.to_f * 2 / (sequence_1.length + sequence_2.length)
      end
      

      【讨论】:

        【解决方案7】:
        Max = Lev_distance(Q,''); //max operations to transform query string to empty string
        PM = (Max - Lev_distance(Q, Mi)) / Max * 100%;
        

        我认为这足以满足您的需求。它对于极值是正确的(完全满足相同和完全不同的字符串)并且是合理的

        【讨论】:

          【解决方案8】:

          我认为更简单的方法可能是:

          from nltk import edit_distance
          
          str1 = 'abc'
          str2 = 'abd'
          edit_dist  = edit_distance(str1,str2)
          len_total = len(str1)+len(str2)
          pct_edit_dist = ((len_total-edit_dist)/len_total)*100
          print(pct_edit_dist)
          

          pct_edit_dist 为 100 表示完全匹配,0 表示不匹配。

          【讨论】:

            猜你喜欢
            • 2017-05-01
            • 2011-07-03
            • 1970-01-01
            • 2012-01-13
            • 2019-04-07
            • 2014-03-07
            • 2021-05-07
            • 2019-05-27
            • 1970-01-01
            相关资源
            最近更新 更多