web-dev-qa-db-ja.com

Pythonの文字列類似性メトリック

2つの文字列の文字列の類似性を見つけたいです。 これ ページにはそれらの例があります。 Pythonには Levenshteinアルゴリズム の実装があります。より良いアルゴリズムはありますか(できればpythonライブラリ)、これらの制約の下で。

  1. 文字列間のあいまい一致を行いたいです。例:matches( 'Hello、All you people'、 'hello、all You peopl')はTrueを返す必要があります
  2. 偽陰性は受け入れられますが、非常にまれな場合を除き、偽陽性は受け入れられません。
  3. これは非リアルタイム設定で行われるため、速度は(あまり)問題になりません。
  4. [編集]複数のWord文字列を比較しています。

私の場合、レーベンシュタイン距離(またはレーベンシュタイン比)以外の何かがより良いアルゴリズムでしょうか?

42
agiliq

シェフィールド大学には、文字列の類似性メトリックに関する優れたリソースがあります。さまざまなメトリックのリスト(レーベンシュタイン以外にも)があり、それらのオープンソース実装があります。それらの多くはPythonに簡単に適応できるはずです。

http://web.archive.org/web/20081224234350/http://www.dcs.shef.ac.uk/~sam/stringmetrics.html

リストの一部を次に示します。

  • ハミング距離
  • レーベンシュタイン距離
  • Needleman-Wunch distanceまたはセラーズアルゴリズム
  • などなど...
20
ariddell

私はそれが同じものではないことを理解していますが、これは十分に近いです:

>>> import difflib
>>> a = 'Hello, All you people'
>>> b = 'hello, all You peopl'
>>> seq=difflib.SequenceMatcher(a=a.lower(), b=b.lower())
>>> seq.ratio()
0.97560975609756095

これを関数として作成できます

def similar(seq1, seq2):
    return difflib.SequenceMatcher(a=seq1.lower(), b=seq2.lower()).ratio() > 0.9

>>> similar(a, b)
True
>>> similar('Hello, world', 'Hi, world')
False
82
Nadia Alramli

このスニペットは、2つの文字列のdifflib、Levenshtein、Sørensen、およびJaccardの類似値を計算します。以下のスニペットでは、対象の文字列がtsvの列[3]および[4]を占めるtsvを繰り返し処理していました。 (pip install python-Levenshteinおよびpip install distance):

import codecs, difflib, Levenshtein, distance

with codecs.open("titles.tsv","r","utf-8") as f:
    title_list = f.read().split("\n")[:-1]

    for row in title_list:

        sr      = row.lower().split("\t")

        diffl   = difflib.SequenceMatcher(None, sr[3], sr[4]).ratio()
        lev     = Levenshtein.ratio(sr[3], sr[4]) 
        sor     = 1 - distance.sorensen(sr[3], sr[4])
        jac     = 1 - distance.jaccard(sr[3], sr[4])

        print diffl, lev, sor, jac
13
duhaime

私は、2つの理由(1)「十分に速い」(動的プログラミングアルゴリズム)と「whoooosh」(ビットバッシング)Cコードが利用可能であり、(2)よく理解されている動作レーベンシュタインは三角形の不等式を満たしているため、例えばBurkhard-Kellerツリー。

しきい値:距離<(1-X)* max(len(string1)、len(string2))の場合にのみ「正」として扱い、自分に合うようにX(類似性係数)を調整する必要があります。 Xを選択する1つの方法は、一致のサンプルを取得し、それぞれに対してXを計算し、X <0.8または0.9の場合を無視し、Xの降順で残りをソートし、正しい結果を挿入して、いくつかを計算することですXのさまざまなレベルのコストの測定。

N.B.あなたの類人猿/ Appleの例は距離2なので、Xは0.6です...何かを必死に探していて、高い偽陰性ペナルティがあった場合、0.75という低いしきい値のみを使用します

7
John Machin

それはあなたの言うことですか?

>>> get_close_matches('appel', ['ape', 'Apple', 'Peach', 'puppy'])
['Apple', 'ape']
>>> import keyword
>>> get_close_matches('wheel', keyword.kwlist)
['while']
>>> get_close_matches('Apple', keyword.kwlist)
[]
>>> get_close_matches('accept', keyword.kwlist)
['except']

http://docs.python.org/library/difflib.html#difflib.get_close_matches を見てください

5

私はこれが同じではないことを知っていますが、比率を調整して十分に類似していない文字列を除外し、探している文字列に最も近い一致を返すことができます。

おそらく、セマンティックの類似性メトリックにもっと興味があるでしょう。

https://www.google.com/search?client=ubuntu&channel=fs&q=semantic+similarity+string+match&ie=utf-8&oe=utf-8

速度は問題ではないが、アルゴリズムの文字列の多くを処理している場合、以下が非常に役立つと言っています。

def spellcheck(self, sentence):
    #return ' '.join([difflib.get_close_matches(Word, wordlist,1 , 0)[0] for Word in sentence.split()])
    return ' '.join( [ sorted( { Levenshtein.ratio(x, Word):x for x in wordlist }.items(), reverse=True)[0][1] for Word in sentence.split() ] )

Difflibよりも約20倍高速です。

https://pypi.python.org/pypi/python-Levenshtein/

レーベンシュタインをインポート

2
John