Найти метрику сходства между двумя строками


284

Как я могу получить вероятность того, что строка похожа на другую строку в 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
Слово, которое вы ищете, это соотношение, а не вероятность.
Инбар Роуз

1
Посмотрите на расстояние Хэмминга .
Диана

2
Фраза «метрика сходства» , но есть несколько метрик сходства (Жаккард, Косинус, Хэмминг, Левеншайн и т. Д.), Поэтому вам нужно указать, какие именно. В частности, вы хотите, чтобы метрика сходства между строками; @hbprotoss перечислил несколько.
СМС

Ответы:


545

Есть встроенный.

from difflib import SequenceMatcher

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

Используй это:

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

43
Смотрите этот большой ответ по сравнению SequenceMatcherпротив python-Levenshteinмодуля. stackoverflow.com/questions/6690739/...
ssoler

1
Интересная статья и инструмент: chairnerd.seatgeek.com/…
Энтони Перо

7
Я очень рекомендую проверить весь difflib doc docs.python.org/2/library/difflib.html там есть get_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

Это сработало отлично. Просто и эффективно. Спасибо :)
Картик Шринивасан


46

Решение № 1: встроенный Python

использовать SequenceMatcher из difflib

Плюсы : нативная библиотека Python, нет необходимости в дополнительном пакете.
минусы : слишком ограниченный, есть много других хороших алгоритмов для сходства строк.

пример :
>>> from difflib import SequenceMatcher
>>> s = SequenceMatcher(None, "abcd", "bcde")
>>> s.ratio()
0.75

Решение № 2: библиотека медуз

Это очень хорошая библиотека с хорошим освещением и несколькими проблемами. он поддерживает:
- Расстояние Левенштейна - Расстояние
Дамерау-Левенштейна
- Расстояние
Яро - Расстояние Яро-Винклера
- Сравнение подходов к рейтингу матчей
- Расстояние Хэмминга

Плюсы : простота в использовании, гамма поддерживаемых алгоритмов, проверено.
минусы : не родная библиотека.

пример :

>>> 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, с некоторыми вспомогательными функциями, которые помогают в определенных ситуациях, когда вы можете захотеть, чтобы две разные строки считались идентичными. Например:

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

но аналог («аппель», «яблоко») выше, чем аналог («аппель», «обезьяна»)
tenstar

1
Ваша функция будет сравнивать данную строку с другими строчками. Мне нужен способ вернуть строку с наибольшим коэффициентом сходства
answerSeeker

1
@SaulloCastro, if self.similar(search_string, item.text()) > 0.80:работает на данный момент. Спасибо,
отвечу Искателю


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'

Использование биопиона или другого пакета биоинформатики является более гибким, чем любая часть стандартной библиотеки 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-sdentifity#python-string-sdentifity Вот несколько примеров;

  • Нормализовано, метрика, сходство и расстояние

  • (Нормализованное) сходство и расстояние

  • Метрические расстояния

  • Опоясывающий лишай (n-грамм) на основе сходства и расстояния
  • Левенштейн
  • Нормализованный Левенштейн
  • Весовой Левенштейн
  • Damerau-Левенштейна
  • Оптимальное выравнивание строк
  • Яро-Винклер
  • Самая длинная общая подпоследовательность
  • Метрическая самая длинная общая подпоследовательность
  • N-Gram
  • Алгоритмы на основе гальки (n-грамм)
  • Q-Gram
  • Косинус сходство
  • Жаккардовый указатель
  • Коэффициент Соренсена-Дайса
  • Коэффициент перекрытия (т. Е. Шимкевич-Симпсон)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.