İki dize arasındaki benzerlik metriğini bulun


284

Bir dizenin Python'daki başka bir dizeye benzer olma olasılığını nasıl elde edebilirim?

0.9 (yani% 90) vb. Gibi bir ondalık değer almak istiyorum. Tercihen standart Python ve kütüphane ile.

Örneğin

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

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

6
Burada "olasılık" ın tam olarak doğru terim olduğunu düşünmüyorum. Her halükarda, bkz. Stackoverflow.com/questions/682367/…
NPE

1
Aradığınız kelime olasılık değil orantır.
Inbar Rose

1
Hamming mesafesine bir göz atın .
Diana

2
İfade 'benzerlik metriği' , ancak birden fazla benzerlik metriği (Jaccard, Cosine, Hamming, Levenshein vb.) Var, bu yüzden hangisini belirtmeniz gerektiğini söyledi. Özellikle dizeler arasında benzerlik metriği istiyorsunuz; @hbprotoss birkaç listeledi.
smci

Yanıtlar:


544

Bir yerleşik var.

from difflib import SequenceMatcher

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

Kullanma:

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

43
Karşılaştıran bu büyük yanıta bakın SequenceMatchervs python-Levenshteinmodülü. stackoverflow.com/questions/6690739/…
ssoler

1
İlginç makale ve araç: chairnerd.seatgeek.com/…
Anthony Perot

7
Özel kontroller ile daha güvenilir bulmama rağmen, tüm difflib doc docs.python.org/2/library/difflib.html orada get_close_matchesyerleşik kontrol etmenizi şiddetle tavsiye ederimsorted(... key=lambda x: difflib.SequenceMatcher(None, x, search).ratio(), ...)sorted(... .get_matching_blocks())[-1] > min_match
ThorSummoner 15:16

2
@ThorSummoner çok kullanışlı bir işleve ( get_closest_matches) dikkat çeker . Aradığın şey olabilir bir kolaylık fonksiyonu, AKA belgeleri okuyun! Benim özel uygulama kötü girdi sağlayan kullanıcıya bazı temel hata kontrolü / raporlama yapıyordum ve bu cevap onlara potansiyel eşleşmeleri ve "benzerlik" ne olduğunu rapor etmek için izin verir . Benzerliği göstermeniz gerekmiyorsa, kesinlikle göz get_closest_matches
atın

Bu mükemmel çalıştı. Basit ve etkili. Teşekkür :)
Karthic Srinivasan


46

1.Çözüm: Python yerleşik

kullanmak SequenceMatcher gelen difflib

artıları : yerli python kütüphanesi, ekstra pakete gerek yok.
eksileri : çok sınırlı, orada dize benzerliği için çok iyi algoritmalar vardır.

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

Çözüm # 2: Denizanası Kütüphanesi

onun iyi kapsama alanı ve az sayıda sorunları ile çok iyi bir kütüphane. destekliyor:
- Levenshtein Mesafesi
- Damerau-Levenshtein Mesafesi
- Jaro Mesafesi
- Jaro-Winkler Mesafesi
- Maç Derecesi Yaklaşım Karşılaştırması
- Hamming Mesafesi

artıları : kullanımı kolay, desteklenen algoritma gamı, test edilmiştir.
eksileri : yerel kütüphane değil.

örnek :

>>> 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 WuzzyPython'da Levenshtein mesafesini uygulayan, iki farklı dizenin aynı olarak değerlendirilmesini isteyebileceğiniz bazı durumlarda yardımcı olacak bazı yardımcı işlevlere sahip bir pakettir . Örneğin:

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

Şunun gibi bir işlev oluşturabilirsiniz:

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

ancak benzer ('appel', 'apple') benzer olandan daha yüksek ('appel', 'maymun')
tenstar

1
İşleviniz belirli bir dizeyi diğer sokmalarla karşılaştırır. En yüksek benzerlik oranına sahip dizeyi döndürmek için bir yol istiyorum
answerSeeker

1
@SaulloCastro, if self.similar(search_string, item.text()) > 0.80:şimdilik çalışıyor. Teşekkürler,
answerSeeker


6

Yerleşik SequenceMatcherbüyük girişte çok yavaş, işte fark eşleştirme yamasıyla nasıl yapılabilir :

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

Not, difflib.SequenceMatcher sadece en uzun bitişik eşleştirme dizisini bulur, bu genellikle istenen şey değildir, örneğin:

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

İki tel arasındaki benzerliği bulmak biyoinformatikte ikili dizi hizalaması kavramı ile yakından ilgilidir. Bunun için biyopthon da dahil olmak üzere birçok özel kütüphane bulunmaktadır . Bu örnek, Needleman Wunsch algoritmasını uygular :

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

Biyopthon veya başka bir biyoinformatik paketi kullanmak, birçok farklı skorlama şeması ve algoritması bulunduğundan, python standart kütüphanesinin herhangi bir kısmından daha esnektir. Ayrıca, neler olduğunu görselleştirmek için eşleşen dizileri alabilirsiniz:

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

Metin benzerlik yöntemlerinin çoğunu ve bunların nasıl hesaplandığını bu bağlantı altında bulabilirsiniz: https://github.com/luozhouyang/python-string-slikeity#python-string-seberity Burada bazı örnekler;

  • Normalleştirilmiş, metrik, benzerlik ve mesafe

  • (Normalize) benzerlik ve mesafe

  • Metrik mesafeler

  • Zona (n-gram) tabanlı benzerlik ve mesafe
  • Levenshtein
  • Normalize Edilmiş Levenshtein
  • Ağırlıklı Levenshtein
  • Damerau-Levenshtein
  • Optimal Dize Hizalama
  • Jaro-Winkler
  • En Uzun Ortak Subququence
  • Metrik En Uzun Ortak Alt Sıra
  • N-gram
  • Shingle (n-gram) tabanlı algoritmalar
  • S-gram
  • Kosinüs benzerliği
  • Jaccard endeksi
  • Sorensen-Zar katsayısı
  • Çakışma katsayısı (yani, Szymkiewicz-Simpson)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.