2つの文字列の文字列の類似性を見つけたいです。 これ ページにはそれらの例があります。 Pythonには Levenshteinアルゴリズム の実装があります。より良いアルゴリズムはありますか(できればpythonライブラリ)、これらの制約の下で。
私の場合、レーベンシュタイン距離(またはレーベンシュタイン比)以外の何かがより良いアルゴリズムでしょうか?
シェフィールド大学には、文字列の類似性メトリックに関する優れたリソースがあります。さまざまなメトリックのリスト(レーベンシュタイン以外にも)があり、それらのオープンソース実装があります。それらの多くはPythonに簡単に適応できるはずです。
http://web.archive.org/web/20081224234350/http://www.dcs.shef.ac.uk/~sam/stringmetrics.html
リストの一部を次に示します。
私はそれが同じものではないことを理解していますが、これは十分に近いです:
>>> 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
このスニペットは、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
私は、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という低いしきい値のみを使用します
それはあなたの言うことですか?
>>> 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 を見てください
私はこれが同じではないことを知っていますが、比率を調整して十分に類似していない文字列を除外し、探している文字列に最も近い一致を返すことができます。
おそらく、セマンティックの類似性メトリックにもっと興味があるでしょう。
速度は問題ではないが、アルゴリズムの文字列の多くを処理している場合、以下が非常に役立つと言っています。
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/
レーベンシュタインをインポート