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

时间:2013-06-30 07:35:24

标签: python probability similarity metric

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

我希望获得一个十进制值,如0.9(意味着90%)等。最好使用标准的Python和库。

e.g。

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

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

13 个答案:

答案 0 :(得分:453)

内置。

from difflib import SequenceMatcher

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

使用它:

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

答案 1 :(得分:59)

我想也许你正在寻找一种描述字符串之间距离的算法。以下是您可以参考的一些内容:

  1. Hamming distance
  2. Levenshtein distance
  3. Damerau–Levenshtein distance
  4. Jaro–Winkler distance

答案 2 :(得分:28)

解决方案#1:Python内置

使用SequenceMatcher

中的difflib

<强>优点:    原生的python库,不需要额外的包 缺点:太有限了,还有很多其他优秀的字符串相似算法。

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

解决方案#2:jellyfish

它是一个非常好的图书馆,覆盖面很好,问题很少。 它支持:
- Levenshtein距离
- Damerau-Levenshtein距离
- Jaro距离
- Jaro-Winkler距离
- 比赛评级方法比较
- 汉明距离

<强>优点:    易于使用,支持的算法范围,经过测试 缺点:不是本机库。

示例

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

答案 3 :(得分:24)

Fuzzy Wuzzy是一个package,它在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

答案 4 :(得分: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))

答案 5 :(得分:7)

套餐distance包括Levenshtein距离:

import distance
distance.levenshtein("lenvestein", "levenshtein")
# 3

答案 6 :(得分:4)

内置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

答案 7 :(得分:4)

请注意,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 algorithm

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

答案 8 :(得分:2)

BLEUscore

<块引用>

BLEU,即双语评估研究,是用于比较的分数 文本到一个或多个参考翻译的候选翻译。

完美匹配的得分为 1.0,而完美匹配的得分为 1.0 结果为 0.0。

虽然是为翻译开发的,但也可以用来评价文本 为一组自然语言处理任务生成。

代码:

import nltk
from nltk.translate import bleu
from nltk.translate.bleu_score import SmoothingFunction
smoothie = SmoothingFunction().method4

C1='Text'
C2='Best'

print('BLEUscore:',bleu([C1], C2, smoothing_function=smoothie))

示例:通过更新 C1 和 C2。

C1='Test' C2='Test'

BLEUscore: 1.0

C1='Test' C2='Best'

BLEUscore: 0.2326589746035907

C1='Test' C2='Text'

BLEUscore: 0.2866227639866161

还可以比较句子的相似度:

C1='It is tough.' C2='It is rough.'

BLEUscore: 0.7348889200874658

C1='It is tough.' C2='It is tough.'

BLEUscore: 1.0

答案 9 :(得分:1)

您可以在以下链接下找到大多数文本相似性方法及其计算方式:https://github.com/luozhouyang/python-string-similarity#python-string-similarity 这里有一些例子;

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

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

  • 公制距离

  • 基于带状疱疹(n-gram)的相似度和距离
  • Levenshtein
  • 标准化Levenshtein
  • Levenshtein加权
  • Damerau-Levenshtein
  • 最佳字符串对齐
  • Jaro-Winkler
  • 最长的公共子序列
  • 公制最长公共子序列
  • N-Gram
  • 基于瓦片(n-gram)的算法
  • Q-Gram
  • 余弦相似度
  • Jaccard索引
  • 索伦森-骰子系数
  • 重叠系数(即Szymkiewicz-Simpson)

答案 10 :(得分:1)

如上所述,有许多度量标准来定义字符串之间的相似性和距离。我将举例说明Jaccard similarityQ-Grams,并举例说明edit distance,给我5美分。

图书馆

from nltk.metrics.distance import jaccard_distance
from nltk.util import ngrams
from nltk.metrics.distance  import edit_distance

Jaccard相似度

1-jaccard_distance(set(ngrams('Apple', 2)), set(ngrams('Appel', 2)))

我们得到:

0.33333333333333337

对于AppleMango

1-jaccard_distance(set(ngrams('Apple', 2)), set(ngrams('Mango', 2)))

我们得到:

0.0

编辑距离

edit_distance('Apple', 'Appel')

我们得到:

2

最后

edit_distance('Apple', 'Mango')

我们得到:

5

Q克上的余弦相似度(q = 2)

另一种解决方案是使用textdistance库。我将提供一个Cosine Similarity

的示例
import textdistance
1-textdistance.Cosine(qval=2).distance('Apple', 'Appel')

我们得到:

0.5

答案 11 :(得分:0)

文本距离:

TextDistance –用于通过许多算法比较两个或多个序列之间距离的python库。它有Textdistance

  • 30多种算法
  • 纯python实现
  • 简单用法
  • 比较两个以上的序列
  • 某些算法在一类中具有多个实现。
  • 可选的numpy用法以实现最大速度。

示例1

import textdistance
textdistance.hamming('test', 'text')

输出:

1

示例2:

import textdistance

textdistance.hamming.normalized_similarity('test', 'text')

输出:

0.75

感谢和欢呼!

答案 12 :(得分:0)

这就是我的想法:

import string

def match(a,b):
    a,b = a.lower(), b.lower()
    error = 0
    for i in string.ascii_lowercase:
            error += abs(a.count(i) - b.count(i))
    total = len(a) + len(b)
    return (total-error)/total

if __name__ == "__main__":
    print(match("pple inc", "Apple Inc."))