Trova la metrica di somiglianza tra due stringhe


284

Come posso ottenere la probabilità che una stringa sia simile a un'altra stringa in Python?

Voglio ottenere un valore decimale come 0,9 (che significa 90%) ecc. Preferibilmente con Python standard e libreria.

per esempio

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

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

6
Non credo che "probabilità" sia piuttosto il termine giusto qui. In ogni caso, vedi stackoverflow.com/questions/682367/…
NPE,

1
La parola che stai cercando è rapporto, non probabilità.
Inbar Rose,

1
Dai un'occhiata alla distanza di Hamming .
Diana,

2
La frase è "metrica di somiglianza" , ma ci sono più metriche di somiglianza (Jaccard, Cosine, Hamming, Levenshein ecc.), Quindi è necessario specificare quale. In particolare, si desidera una metrica di somiglianza tra le stringhe; @hbprotoss ha elencato diversi.
smci,

Risposte:


545

C'è un integrato.

from difflib import SequenceMatcher

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

Usandolo:

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

43
Vedi questa grande risposta confrontando modulo SequenceMatchervs. stackoverflow.com/questions/6690739/...python-Levenshtein
ssoler

1
Articolo e strumento interessante: chairnerd.seatgeek.com/…
Anthony Perot,

7
Consiglio vivamente di consultare l'intero documento difflib docs.python.org/2/library/difflib.html è get_close_matchesintegrato, anche se l'ho trovato sorted(... key=lambda x: difflib.SequenceMatcher(None, x, search).ratio(), ...)più affidabile, con sorted(... .get_matching_blocks())[-1] > min_matchcontrolli personalizzati
ThorSummoner,

2
@ThorSummoner richiama l'attenzione su una funzione molto utile ( get_closest_matches). È una funzione di praticità che potrebbe essere ciò che stai cercando, AKA leggi i documenti! Nella mia particolare applicazione stavo eseguendo alcuni controlli di base sugli errori / segnalando all'utente fornendo un input errato, e questa risposta mi consente di segnalare loro le potenziali corrispondenze e quale fosse la "somiglianza". Se non hai bisogno di mostrare la somiglianza, però, dai un'occhiata sicuramenteget_closest_matches
svenevs,

Questo ha funzionato perfettamente. Semplice ed efficace Grazie :)
Karthic Srinivasan,


46

Soluzione n. 1: Python integrato

usa SequenceMatcher da difflib

pro : libreria nativa di Python, nessun pacchetto aggiuntivo necessario.
contro : troppo limitato, ci sono tanti altri buoni algoritmi per la somiglianza delle stringhe là fuori.

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

Soluzione n. 2: libreria di meduse

è un'ottima biblioteca con una buona copertura e pochi problemi. supporta:
- Distanza di Levenshtein - Distanza di
Damerau-Levenshtein
- Distanza di
Jaro - Distanza di Jaro-Winkler
- Confronto di approccio di valutazione della corrispondenza
- Distanza di Hamming

pro : facile da usare, gamma di algoritmi supportati, testato.
contro : non libreria nativa.

esempio :

>>> 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è un pacchetto che implementa la distanza di Levenshtein in Python, con alcune funzioni di aiuto per aiutare in determinate situazioni in cui potresti voler considerare identiche due stringhe distinte. Per esempio:

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

Puoi creare una funzione come:

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

ma similar ('appel', 'apple') è più alto di similar ('appel', 'ape')
tenstar

1
La tua funzione confronterà una determinata stringa con altre punture. Voglio un modo per restituire la stringa con il più alto rapporto di somiglianza
answerSeeker

1
@SaulloCastro, if self.similar(search_string, item.text()) > 0.80:funziona per ora. Grazie,
answerSeeker,


6

Il builtin SequenceMatcherè molto lento su input di grandi dimensioni, ecco come si può fare con 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

Nota, trova difflib.SequenceMatcher solo la sottosequenza di corrispondenza contigua più lunga, spesso non è ciò che desideri, ad esempio:

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

Trovare la somiglianza tra due stringhe è strettamente correlato al concetto di allineamento della sequenza a coppie in bioinformatica. Ci sono molte librerie dedicate per questo incluso biopython . Questo esempio implementa l' algoritmo Needleman Wunsch :

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

L'uso di biopython o di un altro pacchetto bioinformatico è più flessibile di qualsiasi parte della libreria standard di Python poiché sono disponibili molti schemi e algoritmi di punteggio diversi. Inoltre, puoi effettivamente ottenere le sequenze corrispondenti per visualizzare ciò che sta accadendo:

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

Puoi trovare la maggior parte dei metodi di somiglianza testuale e come vengono calcolati sotto questo link: https://github.com/luozhouyang/python-string-similarity#python-string-similarity Ecco alcuni esempi;

  • Normalizzato, metrico, somiglianza e distanza

  • Somiglianza (normalizzata) e distanza

  • Distanze metriche

  • Somiglianza e distanza basate su fuoco di Sant'Antonio (n-grammo)
  • Levenshtein
  • Levenshtein normalizzato
  • Levenshtein ponderato
  • Damerau-Levenshtein
  • Allineamento ottimale delle stringhe
  • Jaro-Winkler
  • Conseguenza comune più lunga
  • Conseguenza comune più lunga metrica
  • N-Gram
  • Algoritmi basati su ghiaia (n-grammo)
  • Q-Gram
  • Somiglianza del coseno
  • Indice Jaccard
  • Coefficiente Dadi Sorensen
  • Coefficiente di sovrapposizione (ovvero Szymkiewicz-Simpson)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.