Знайдіть метрику подібності між двома рядками


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
Слово, яке ви шукаєте, - співвідношення, а не ймовірність.
Inbar Rose

1
Погляньте на відстань Хеммінга .
Діана

2
Фраза є "метрикою подібності" , але є кілька метрик подібності (Жаккард, Косін, Хеммінг, Левеншейн тощо), тому вам потрібно вказати, яка. Зокрема, ви хочете, щоб показник подібності між рядками; @hbprotoss перерахував декілька.
smci

Відповіді:


544

Є вбудований.

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
вважаю

2
@ThorSummoner привертає увагу до дуже корисної функції ( get_closest_matches). Це функція зручності, яка може бути те, що ви шукаєте, AKA читайте документи! У моїй конкретній програмі я робив деякі основні перевірки помилок / звітування перед користувачем, які надавали погані дані, і ця відповідь дозволяє мені повідомляти їм про можливі збіги та про те, що таке "схожість". Якщо вам не потрібно відображати подібність, проте, обов'язково перевіряйтеget_closest_matches
svenevs

Це спрацювало чудово. Простий і ефективний.
Дякую


46

Рішення №1: Вбудований Python

використовувати SequenceMatcher від difflib

плюси : рідна бібліотека пітона, не потрібен додатковий пакет.
Мінуси : занадто обмежений, існує так багато інших хороших алгоритмів для подібності рядків.

приклад :
>>> 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 :

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

Пошук подібності між двома рядками тісно пов'язаний з концепцією вирівнювання парної послідовності в біоінформатиці. Для цього існує багато виділених бібліотек, включаючи біопітон . Цей приклад реалізує алгоритм 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-s подобниity#python-string- s similarity Ось кілька прикладів;

  • Нормалізована, метрична, подібність та відстань

  • (Нормалізовано) подібність та відстань

  • Метричні відстані

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