【问题标题】:String similarity metrics in PythonPython中的字符串相似度度量
【发布时间】:2009-09-24 11:43:00
【问题描述】:

我想找出两个字符串之间的字符串相似度。 This 页面有其中一些示例。 Python 的实现为Levenshtein algorithm。在这些限制下是否有更好的算法(希望是 python 库)。

  1. 我想在字符串之间进行模糊匹配。例如matches('Hello, All you people', 'hello, all You people') 应该返回True
  2. 假阴性是可以接受的,假阳性是可以接受的,极少数情况除外。
  3. 这是在非实时设置中完成的,因此速度不是(太多)问题。
  4. [编辑] 我在比较多字串。

除了 Levenshtein 距离(或 Levenshtein 比率)以外的其他算法是否适合我的情况?

【问题讨论】:

  • 关于第 2 点:阅读:en.wikipedia.org/wiki/Receiver_operating_characteristic。根据您的第 2 点,最好的相似度指标是仅调用相同的字符串相似。超出此范围的任何模糊都会产生误报。
  • 嗯.. 那么接近人类智能的无错误就是我要寻找的。例如。人类可以得出结论,Appel 可能与 Apple 相同,但 Ape 不是。可能没有把我的观点说清楚。
  • (1) “无错误”是不可能的,即使完全匹配也是如此。 “苹果”(水果)!=“苹果”(电脑等制造商)。 (2)如果“接近人类的智能”可用,它既不是在一大堆代码中,也不是免费的。 (3) 考虑使用允许换位的方法——将 appel/apple 的排名高于 ape/apple 和ape/appel。

标签: python algorithm string levenshtein-distance


【解决方案1】:

我意识到这不是一回事,但这已经足够接近了:

>>> import difflib
>>> a = 'Hello, All you people'
>>> b = 'hello, all You peopl'
>>> seq=difflib.SequenceMatcher(a=a.lower(), b=b.lower())
>>> seq.ratio()
0.97560975609756095

你可以把它做成一个函数

def similar(seq1, seq2):
    return difflib.SequenceMatcher(a=seq1.lower(), b=seq2.lower()).ratio() > 0.9

>>> similar(a, b)
True
>>> similar('Hello, world', 'Hi, world')
False

【讨论】:

    【解决方案2】:

    谢菲尔德大学有一个很好的字符串相似度指标资源。它有一个各种指标的列表(不仅仅是 Levenshtein),并且有它们的开源实现。看起来它们中的许多应该很容易适应 Python。

    http://web.archive.org/web/20081224234350/http://www.dcs.shef.ac.uk/~sam/stringmetrics.html

    这里有一些列表:

    • 汉明距离
    • Levenshtein 距离
    • Needleman-Wunch 距离或卖方算法
    • 还有更多...

    【讨论】:

      【解决方案3】:

      这个 sn-p 将计算两个字符串的 difflib、Levenshtein、Sørensen 和 Jaccard 相似度值。在下面的 sn-p 中,我正在迭代一个 tsv,其中感兴趣的字符串占据了 tsv 的 [3][4] 列。 (pip install python-Levenshteinpip install distance):

      import codecs, difflib, Levenshtein, distance
      
      with codecs.open("titles.tsv","r","utf-8") as f:
          title_list = f.read().split("\n")[:-1]
      
          for row in title_list:
      
              sr      = row.lower().split("\t")
      
              diffl   = difflib.SequenceMatcher(None, sr[3], sr[4]).ratio()
              lev     = Levenshtein.ratio(sr[3], sr[4]) 
              sor     = 1 - distance.sorensen(sr[3], sr[4])
              jac     = 1 - distance.jaccard(sr[3], sr[4])
      
              print diffl, lev, sor, jac
      

      【讨论】:

      • 运行此程序时出现“IndexError: list index out of range”错误。为什么我会得到它?
      • @FeyziBagirov 你能用你的脚本和输入发布一个 github 要点吗?
      【解决方案4】:

      我会使用 Levenshtein 距离,或者所谓的 Damerau 距离(考虑了转置)而不是 difflib 的东西,原因有两个:(1)“足够快”(动态编程算法)和“哇哦”(bit-抨击)C 代码可用和(2)易于理解的行为,例如Levenshtein 满足三角不等式,因此可用于例如Burkhard-Keller 树。

      阈值:仅当距离

      注意您的猿/苹果示例的距离为 2,因此 X 为 0.6 ...如果我拼命寻找某些东西并且有很高的假阴性惩罚,我只会使用低至 0.75 的阈值

      【讨论】:

        【解决方案5】:

        你是这个意思吗?

        >>> get_close_matches('appel', ['ape', 'apple', 'peach', 'puppy'])
        ['apple', 'ape']
        >>> import keyword
        >>> get_close_matches('wheel', keyword.kwlist)
        ['while']
        >>> get_close_matches('apple', keyword.kwlist)
        []
        >>> get_close_matches('accept', keyword.kwlist)
        ['except']
        

        http://docs.python.org/library/difflib.html#difflib.get_close_matches

        【讨论】:

        • 谢谢。这可能会给我一些好主意,但不是我正在寻找的get_close_matches('appel', ['ape', 'peach', 'puppy']) 让我成为猿。我可以设置截止值,但从一些快速实验来看,误报太常见了。
        【解决方案6】:

        我知道这不一样,但您可以调整比率以过滤掉不够相似的字符串,并返回与您要查找的字符串最接近的匹配项。

        也许您会对语义相似度指标更感兴趣。

        https://www.google.com/search?client=ubuntu&channel=fs&q=semantic+similarity+string+match&ie=utf-8&oe=utf-8

        我知道您说过速度不是问题,但如果您正在为您的算法处理大量字符串,那么下面的内容非常有帮助。

        def spellcheck(self, sentence):
            #return ' '.join([difflib.get_close_matches(word, wordlist,1 , 0)[0] for word in sentence.split()])
            return ' '.join( [ sorted( { Levenshtein.ratio(x, word):x for x in wordlist }.items(), reverse=True)[0][1] for word in sentence.split() ] )
        

        它比 difflib 快大约 20 倍。

        https://pypi.python.org/pypi/python-Levenshtein/

        导入文石

        【讨论】:

          猜你喜欢
          • 2019-05-01
          • 2016-07-15
          • 2015-10-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-10
          • 2021-10-12
          相关资源
          最近更新 更多