最优对齐的字符串相似度

问题描述

算法的预期行为

我有两个字符串 ab,其中 a 是较短的字符串。我想找到与 b 相似度最大的 a 子串。子串必须是 len(a),或者必须放在 b 的末尾。 例如对于以下两个字符串:

a = "aa"
b = "bbaba"

b 的可能子串是

"bb"
"ba"
"ab"
"ba"
"a"
""

编辑距离定义为插入和删除数量。替换是不可能的(必须使用插入 + 删除)。根据以下等式计算两个字符串之间的相似度:norm = 1 - distance / (len(a) + len(substring))。 所以上面的子字符串将提供以下结果:

"bb" -> 2 DEL + 2 INS -> 1 - 4 / 4 = 0
"ba" -> 1 DEL + 1 INS -> 1 - 2 / 4 = 0.5
"ab" -> 1 DEL + 1 INS -> 1 - 2 / 4 = 0.5
"ba" -> 1 DEL + 1 INS -> 1 - 2 / 4 = 0.5
"a"  ->         1 INS -> 1 - 1 / 3 = 0.66
""   ->         2 INS -> 1 - 2 / 2 = 0

所以算法应该返回 0.66。

不同的实现

类似的比例由 Python 库 fuzzywuzzyfuzz.partial_ratio 的形式实现。它分两步计算比率:

  1. 使用 difflib.SequenceMatcher.get_matching_blocks 搜索较长序列中的匹配子序列

  2. 从匹配的子序列开始计算 len(shorter_string) 的子字符串的比率并返回最大比率

这真的很慢,所以它在可用时使用python-Levenshtein进行此相似度计算。这会根据 Levenshtein 距离执行相同的计算,但速度更快。然而,在边缘情况下,用于比率计算的计算匹配块是完全错误的(参见 issue 16),当正确性相关时,这不会使其成为合适的替代品。

当前实现

我目前将 difflib 的 C++ 端口与权重插入 = 1、删除 = 1 和替换 = 2 的 Levenshtein 距离的快速位并行实现结合使用。当前的实现可以在这里找到:

问题

有没有更快的算法来计算这种相似度。要求是:

  • 仅使用替换/插入(或赋予替换权重为 2,具有类似效果
  • 允许在较长字符串的开头有一个间隙
  • 允许在较长字符串的末尾有一个间隙,只要剩余的子字符串不会变得比较短字符串的长度更短。
  • 它强制执行,子串具有相似的长度(当它不在最后时),因此它匹配 fuzzywuzzy 的行为,但是当它允许匹配更长的子序列时也可以:例如对于 aaba:aaa 这意味着允许使用 aaba 而不是 aab 作为最佳子序列。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)