ค้นหาเมทริกความคล้ายคลึงกันระหว่างสองสตริง


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
ลองดูที่ระยะ Hamming
Diana

2
วลีดังกล่าวเป็น'ความคล้ายคลึงกันของตัวชี้วัด'แต่มีตัวชี้วัดความคล้ายคลึงกันหลายตัว (Jaccard, Cosine, Hamming, Levenshein ฯลฯ ) กล่าวไว้ดังนั้นคุณต้องระบุว่า คุณต้องการให้เมทริกความคล้ายคลึงกันระหว่างสตริงโดยเฉพาะ @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/…
Anthony Perot

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) มันเป็นฟังก์ชั่นอำนวยความสะดวกที่อาจเป็นสิ่งที่คุณกำลังมองหา AKA อ่านเอกสาร! ในแอปพลิเคชันของฉันโดยเฉพาะฉันทำการตรวจสอบข้อผิดพลาดพื้นฐาน / รายงานไปยังผู้ใช้ที่ให้ข้อมูลที่ไม่ถูกต้องและคำตอบนี้ช่วยให้ฉันสามารถรายงานการจับคู่ที่เป็นไปได้และสิ่งที่ "คล้ายคลึงกัน" หากคุณไม่จำเป็นต้องแสดงความคล้ายคลึงกัน แต่แน่นอนตรวจสอบget_closest_matches
svenevs

มันทำงานได้อย่างสมบูรณ์แบบ ง่ายและมีประสิทธิภาพ ขอบคุณ :)
Karthic Srinivasan


46

โซลูชัน # 1: Python ในตัว

ใช้SequenceMatcherจากdifflib

ข้อดี : คลังหลามพื้นเมืองไม่จำเป็นต้องมีแพ็คเกจเพิ่มเติม
ข้อเสีย : จำกัด เกินไปมีอัลกอริธึมที่ดีอื่น ๆ อีกมากมายสำหรับความคล้ายคลึงกันของสตริง

ตัวอย่าง :
>>> from difflib import SequenceMatcher
>>> s = SequenceMatcher(None, "abcd", "bcde")
>>> s.ratio()
0.75

โซลูชัน # 2: ห้องสมุดแมงกะพรุน

มันเป็นห้องสมุดที่ดีมากและมีความครอบคลุมดี มันรองรับ:
- ระยะทาง Levenshtein - ระยะทาง
Damerau-Levenshtein
- ระยะทาง
Jaro - ระยะทางJaro-Winkler
- คะแนนการแข่งขันการเปรียบเทียบวิธีการ
- ระยะทาง Hamming

ข้อดี : ใช้งานง่ายช่วงเสียงของอัลกอริทึมที่รองรับการทดสอบ
ข้อเสีย : ไม่ใช่ห้องสมุดท้องถิ่น

ตัวอย่าง :

>>> 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เป็นแพ็คเกจที่ใช้ระยะทางของ Levenshtein ใน 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))

แต่ที่คล้ายกัน ('appel', 'apple') จะสูงกว่าที่คล้ายกัน ('appel', 'ape')
tenstar

1
ฟังก์ชั่นของคุณจะเปรียบเทียบสตริงที่กำหนดกับ stings อื่น ๆ ฉันต้องการวิธีคืนสตริงด้วยอัตราส่วนความคล้ายคลึงกันสูงสุด
answerSeeker

1
@SaulloCastro ใช้if self.similar(search_string, item.text()) > 0.80:งานได้ตอนนี้ ขอบคุณ
answerSeeker


6

builtin SequenceMatcherช้ามากในการป้อนข้อมูลขนาดใหญ่นี่คือวิธีที่สามารถทำได้ด้วยdiff-match-patch-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'

การใช้ biopython หรือชุดชีวสารสนเทศศาสตร์อื่นมีความยืดหยุ่นมากกว่าส่วนใดส่วนหนึ่งของห้องสมุดมาตรฐานของไพ ธ อนเนื่องจากมีโครงร่างการให้คะแนนและอัลกอริธึมต่าง ๆ มากมาย นอกจากนี้คุณยังสามารถรับลำดับการจับคู่เพื่อให้เห็นภาพว่าเกิดอะไรขึ้น:

>>> 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-similarity#python-string-similarity นี่คือตัวอย่างบางส่วน;

  • ทำให้เป็นมาตรฐานตัวชี้วัดความคล้ายคลึงกันและระยะทาง

  • (Normalized) ความคล้ายคลึงกันและระยะทาง

  • ระยะทางเมตริก

  • งูสวัด (n-gram) มีความคล้ายคลึงและระยะทาง
  • Levenshtein
  • Levenshtein ปกติ
  • Levenshtein แบบถ่วงน้ำหนัก
  • Damerau Levenshtein-
  • การจัดตำแหน่งสตริงที่เหมาะสมที่สุด
  • Jaro-เคลอร์
  • ผลที่ตามมายาวนานที่สุด
  • ตัวชี้วัดที่ตามมายาวนานที่สุด
  • N-แกรม
  • อัลกอริทึมที่ใช้ Shingle (n-gram)
  • Q-แกรม
  • ความคล้ายคลึงโคไซน์
  • ดัชนี Jaccard
  • สัมประสิทธิ์ Sorensen-Dice
  • ค่าสัมประสิทธิ์ซ้อนทับกัน (เช่น Szymkiewicz-Simpson)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.