查找两个字符串之间的相似性度量


283

如何获得一个字符串与Python中另一个字符串相似的概率?

我想得到一个十进制值,例如0.9(表示90%)等。最好使用标准Python和库。

例如

similar("Apple","Appel") #would have a high prob.

similar("Apple","Mango") #would have a lower prob.

6
我认为“概率”在这里不是正确的术语。无论如何,请参见stackoverflow.com/questions/682367/…–
NPE

1
您要查找的单词是比率,而不是概率。
Inbar Rose 2013年


2
这个短语是“相似性指标”,但是说有多个相似性指标(Jaccard,Cosine,Hamming,Levenshein等),因此您需要指定哪个。具体来说,您需要字符串之间的相似性度量;@hbprotoss列出了几个。
smci

Answers:


541

有一个内置的。

from difflib import SequenceMatcher

def similar(a, b):
    return SequenceMatcher(None, a, b).ratio()

使用它:

>>> similar("Apple","Appel")
0.8
>>> similar("Apple","Mango")
0.0

42
看到这个伟大的答案比较SequenceMatcherVS python-Levenshtein模块。stackoverflow.com/questions/6690739/…–
ssoler

1
有趣的文章和工具:chairnerd.seatgeek.com/…–
安东尼·佩罗

7
我强烈建议您检查整个difflib doc docs.python.org/2/library/difflib.htmlget_close_matches,尽管我发现sorted(... key=lambda x: difflib.SequenceMatcher(None, x, search).ratio(), ...)更可靠,但还是内置了自定义sorted(... .get_matching_blocks())[-1] > min_match检查功能
ThorSummoner

2
@ThorSummoner会引起注意一个非常有用的功能(get_closest_matches)。这是一个便捷功能,可能就是您想要的,请阅读文档!在我的特定应用程序中,我正在对提供错误输入的用户进行一些基本的错误检查/报告,并且此答案使我可以向他们报告潜在的匹配以及 “相似性”是什么。但是,如果您不需要显示相似性,请一定要查看一下get_closest_matches
svenevs

这工作得很好。简单有效。Thankyou :)
Karthic Srinivasan


45

解决方案1:内置Python

使用SequenceMatcherdifflib

优点:本地python库,不需要额外的软件包。
缺点:太有限了,还有很多其他的用于字符串相似性的好的算法。

例如
>>> from difflib import SequenceMatcher
>>> s = SequenceMatcher(None, "abcd", "bcde")
>>> s.ratio()
0.75

解决方案2:水母

它是一个很好的图书馆,覆盖面广,几乎没有问题。它支持:
-莱文斯坦距离
- Damerau-Levenshtein距离
-哈罗距离
-哈罗-温克勒距离
-比赛评分方法比较
-海明距离

优点:易于使用,所支持算法的色域经过测试。
缺点:不是本机库。

例如

>>> import jellyfish
>>> jellyfish.levenshtein_distance(u'jellyfish', u'smellyfish')
2
>>> jellyfish.jaro_distance(u'jellyfish', u'smellyfish')
0.89629629629629637
>>> jellyfish.damerau_levenshtein_distance(u'jellyfish', u'jellyfihs')
1

26

Fuzzy Wuzzy是一个在python中实现Levenshtein距离的软件包,并提供了一些帮助程序功能以在某些情况下提供帮助,在某些情况下,您可能希望将两个不同的字符串视为相同。例如:

>>> fuzz.ratio("fuzzy wuzzy was a bear", "wuzzy fuzzy was a bear")
    91
>>> fuzz.token_sort_ratio("fuzzy wuzzy was a bear", "wuzzy fuzzy was a bear")
    100

9

您可以创建如下函数:

def similar(w1, w2):
    w1 = w1 + ' ' * (len(w2) - len(w1))
    w2 = w2 + ' ' * (len(w1) - len(w2))
    return sum(1 if i == j else 0 for i, j in zip(w1, w2)) / float(len(w1))

但相近('appel','apple')高于相近('appel','ape')
tenstar 2013年

1
您的函数会将给定的字符串与其他字符串进行比较。我想要一种返回相似度最高的字符串的方法
answerSeeker

1
@SaulloCastro,if self.similar(search_string, item.text()) > 0.80:现在工作。谢谢,
answerSeeker '17


6

对于SequenceMatcher大输入量,内置函数非常慢,这是使用diff-match-patch可以完成的方法:

from diff_match_patch import diff_match_patch

def compute_similarity_and_diff(text1, text2):
    dmp = diff_match_patch()
    dmp.Diff_Timeout = 0.0
    diff = dmp.diff_main(text1, text2, False)

    # similarity
    common_text = sum([len(txt) for op, txt in diff if op == 0])
    text_length = max(len(text1), len(text2))
    sim = common_text / text_length

    return sim, diff

5

注意,difflib.SequenceMatcher 找到最长的连续匹配子序列,这通常不是所希望的,例如:

>>> a1 = "Apple"
>>> a2 = "Appel"
>>> a1 *= 50
>>> a2 *= 50
>>> SequenceMatcher(None, a1, a2).ratio()
0.012  # very low
>>> SequenceMatcher(None, a1, a2).get_matching_blocks()
[Match(a=0, b=0, size=3), Match(a=250, b=250, size=0)]  # only the first block is recorded

寻找两个字符串之间的相似性与生物信息学中成对序列比对的概念密切相关。有很多专用的库,包括biopython。这个例子实现了Needleman Wunsch算法

>>> from Bio.Align import PairwiseAligner
>>> aligner = PairwiseAligner()
>>> aligner.score(a1, a2)
200.0
>>> aligner.algorithm
'Needleman-Wunsch'

使用biopython或其他生物信息学软件包比python标准库的任何部分都更加灵活,因为可以使用许多不同的评分方案和算法。另外,您实际上可以获取匹配序列以可视化正在发生的事情:

>>> alignment = next(aligner.align(a1, a2))
>>> alignment.score
200.0
>>> print(alignment)
Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-Apple-
|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-|||-|-
App-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-elApp-el

0

你可以发现,大部分的文本类似方法,以及它们是如何此链接下式计算:https://github.com/luozhouyang/python-string-similarity#python-string-similarity 下面一些例子;

  • 归一化,度量,相似度和距离

  • (归一化)相似度和距离

  • 公制距离

  • 基于带状疱疹(n-gram)的相似度和距离
  • 莱文施泰因
  • 标准化莱文施泰因
  • 加权Levenshtein
  • Damerau-Levenshtein
  • 最佳字符串对齐
  • 杰罗·温克勒
  • 最长公共子序列
  • 公制最长公共子序列
  • N-格拉姆
  • 基于碎片(n-gram)的算法
  • Q-Gram
  • 余弦相似度
  • 雅卡指数
  • Sorensen-Dice系数
  • 重叠系数(即,Szymkiewicz-Simpson)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.