用于模糊字符串比较的好 Python 模块? [关闭]

Posted

技术标签:

【中文标题】用于模糊字符串比较的好 Python 模块? [关闭]【英文标题】:Good Python modules for fuzzy string comparison? [closed] 【发布时间】:2010-10-15 12:08:00 【问题描述】:

我正在寻找一个可以进行简单模糊字符串比较的 Python 模块。具体来说,我想要字符串相似程度的百分比。我知道这可能是主观的,所以我希望找到一个可以进行位置比较以及最长相似字符串匹配等的库。

基本上,我希望找到足够简单的东西来产生单个百分比,同时仍然足够可配置,以便我可以指定要执行的比较类型。

【问题讨论】:

虽然不是特定于 Python,但这里有一个关于类似字符串算法的问题:***.com/questions/451884/similar-string-algorithm/… Text difference algorithm的可能重复 【参考方案1】:

Levenshtein Python 扩展和 C 库。

https://github.com/ztane/python-Levenshtein/

Levenshtein Python C 扩展模块包含快速函数 的计算 - Levenshtein(编辑)距离和编辑操作 - 字符串相似度 - 近似中值字符串,通常是字符串平均 - 字符串序列和集合相似度 它支持普通字符串和 Unicode 字符串。

$ pip install python-levenshtein
...
$ python
>>> import Levenshtein
>>> help(Levenshtein.ratio)
ratio(...)
    Compute similarity of two strings.

    ratio(string1, string2)

    The similarity is a number between 0 and 1, it's usually equal or
    somewhat higher than difflib.SequenceMatcher.ratio(), becuase it's
    based on real minimal edit distance.

    Examples:
    >>> ratio('Hello world!', 'Holly grail!')
    0.58333333333333337
    >>> ratio('Brian', 'Jesus')
    0.0

>>> help(Levenshtein.distance)
distance(...)
    Compute absolute Levenshtein distance of two strings.

    distance(string1, string2)

    Examples (it's hard to spell Levenshtein correctly):
    >>> distance('Levenshtein', 'Lenvinsten')
    4
    >>> distance('Levenshtein', 'Levensthein')
    2
    >>> distance('Levenshtein', 'Levenshten')
    1
    >>> distance('Levenshtein', 'Levenshtein')
    0

【讨论】:

只是想指出,对于该线程的未来读者,他们恰好在他们的项目中使用 NLTK,nltk.metrics.edit_distance('string1', 'string2') 将计算 string1string2 之间的 Levenshtein 距离。因此,如果您像我一样使用 NLTK,除此之外,您可能不需要下载 Levenshtein 库。干杯 现在可以通过 PyPi 获得 虽然 NLTK 有 edit_distance 方法,但它是纯 python。如果您大量使用它,python-levenshtein 或 jellyfish 都可以提供巨大的加速...(在我的设置中,我测量了 >10 次) 可以在pypi.python.org/pypi/python-Levenshtein找到稍新的软件包版本 PyPi 包也新支持 Python 3 (0.11.1)【参考方案2】:

Jellyfish 是一个 Python 模块,它支持许多字符串比较指标,包括语音匹配。与 Jellyfish 的实现相比,Levenstein 编辑距离的纯 Python 实现相当慢。

示例用法:

import jellyfish

>>> jellyfish.levenshtein_distance('jellyfish', 'smellyfish')
2 
>>> jellyfish.jaro_distance('jellyfish', 'smellyfish')
0.89629629629629637
>>> jellyfish.damerau_levenshtein_distance('jellyfish', 'jellyfihs')
1
>>> jellyfish.metaphone('Jellyfish')
'JLFX'
>>> jellyfish.soundex('Jellyfish')
'J412'
>>> jellyfish.nysiis('Jellyfish')
'JALYF'
>>> jellyfish.match_rating_codex('Jellyfish')
'JLLFSH'`

【讨论】:

这看起来像一个很棒的库,因为它有 几个 字符串比较算法,而不仅仅是一个:Levenshtein 距离、Damerau-Levenshtein 距离、Jaro 距离、Jaro-Winkler 距离、匹配评分方法比较,汉明距离 我很懒,点击链接很难。答案中的例子会很棒。 n.b. Jellyfish 不能很好地处理 unicode 字符串 是否可以将匹配示例添加到水母库中?换句话说,我们希望库将某些特定的词对分类为匹配?【参考方案3】:

这是一个用于计算两个单词中最长公共子串的 python 脚本(可能需要调整以适用于多单词短语):

def lcs(word1, word2):

    w1 = set(word1[i:j] for i in range(0, len(word1))
             for j in range(1, len(word1) + 1))

    w2 = set(word2[i:j] for i in range(0, len(word2))
             for j in range(1, len(word2) + 1))

    common_subs = w1.intersection(w2)

    sorted_cmn_subs = sorted([
        (len(str), str) for str in list(common_subs)
        ])

    return sorted_cmn_subs.pop()[1]

【讨论】:

【参考方案4】:

我使用 Seat Geek 的 Fuzzy Wuzzy 取得了巨大成功。

https://github.com/seatgeek/fuzzywuzzy

具体是token set ratio函数……

他们还写了一篇关于模糊字符串匹配过程的精彩文章:

http://seatgeek.com/blog/dev/fuzzywuzzy-fuzzy-string-matching-in-python

【讨论】:

【参考方案5】:

看看Fuzzy 模块。它具有用于 soundex、NYSIIS 和双变音器的快速(用 C 语言编写)算法。

很好的介绍可以在:http://www.informit.com/articles/article.aspx?p=1848528

【讨论】:

【参考方案6】:

我正在使用double-metaphone,它就像一个魅力。

一个例子:

>>> dm(u'aubrey')
('APR', '')
>>> dm(u'richard')
('RXRT', 'RKRT')
>>> dm(u'katherine') == dm(u'catherine')
True

更新: 水母也有。属于语音编码。

【讨论】:

【参考方案7】:

这是使用 Charicar 的 simhash 的方法,这也适用于长文档,当您更改文档中的单词顺序时,它也会检测到 100% 的相似度

http://blog.simpliplant.eu/calculating-similarity-between-text-strings-in-python/

【讨论】:

【参考方案8】:

另一种选择是使用最近发布的包FuzzyWuzzy。包支持的各种功能在this blogpost中也有描述。

【讨论】:

【参考方案9】:

正如nosklo 所说,使用Python 标准库中的difflib 模块。

difflib 模块可以使用SequenceMatcher() 对象的ratio() 方法返回序列相似性的度量。相似度以 0.0 到 1.0 范围内的浮点数形式返回。

>>> import difflib

>>> difflib.SequenceMatcher(None, 'abcde', 'abcde').ratio()
1.0

>>> difflib.SequenceMatcher(None, 'abcde', 'zbcde').ratio()
0.80000000000000004

>>> difflib.SequenceMatcher(None, 'abcde', 'zyzzy').ratio()
0.0

【讨论】:

对 SequenceMatcher 印象不深。它给 David/Daved 的分数与给 David/david 的分数相同。 Levenshtein 距离也会遇到同样的问题。如果你不关心这种情况,你应该在比较它们之前对每个参数调用 lower()。【参考方案10】:

还有 Google 自己的 google-diff-match-patch(“目前在 Java、javascript、C++ 和 Python 中可用”)。

(无法评论,因为我自己只用过python的difflib)

【讨论】:

【参考方案11】:

我喜欢nosklo's answer;另一种方法是Damerau-Levenshtein distance:

“在信息论和计算机科学中,Damerau-Levenshtein 距离是两个字符串之间的‘距离’(字符串度量),即有限的符号序列,通过计算将一个字符串转换为其他,其中操作定义为单个字符的插入、删除或替换,或两个字符的转置。"

Wikibooks 的 Python 实现:

def lev(a, b):
    if not a: return len(b)
    if not b: return len(a)
    return min(lev(a[1:], b[1:])+(a[0] != b[0]), \
    lev(a[1:], b)+1, lev(a, b[1:])+1)

更多来自维基教科书, 这会给你longest common substring (LCS) 的长度:

def LCSubstr_len(S, T):
    m = len(S); n = len(T)
    L = [[0] * (n+1) for i in xrange(m+1)]
    lcs = 0
    for i in xrange(m):
        for j in xrange(n):
            if S[i] == T[j]:
                L[i+1][j+1] = L[i][j] + 1
                lcs = max(lcs, L[i+1][j+1])
    return lcs

【讨论】:

谢谢,我在最初的搜索中发现了一些关于 Levenshtein 的信息,但是这些例子太模糊了。你的回答很好。 我选择了这个,因为它给了我一个很好的标量数字,我可以使用它并用于阈值。【参考方案12】:

difflib可以做到。

文档中的示例:

>>> 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']

检查一下。它还有其他功能可以帮助您构建自定义内容。

【讨论】:

+1 不错,我不记得以前见过这个 +1:很高兴被介绍给我以前没有使用过的模块。 其实我之前也用过difflib,但是发现不能只要求百分比匹配量。不过已经有一段时间了。 @Soviut:例如difflib.SequenceMatcher(None, 'foo', 'bar').ratio() 返回一个介于 0-1 之间的值,可以解释为匹配百分比。对吗? 您通过将我定向到 get_close_matches() 为我节省了大量工作

以上是关于用于模糊字符串比较的好 Python 模块? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

Python中的好习惯或坏习惯:在文件中间导入[重复]

python模糊匹配库能否定制匹配关系

python的库有多少个?python有多少个模块?

用于 Python 的 MySQL 模块

python模块之re模块

趣玩Python第16关:3个技巧掌握正则