Python でファジー文字列を照合する
今日は、Python でファジー文字列マッチングを可能にする thefuzz
ライブラリの使用方法を学びます。 さらに、ファジー文字列ロジックの助けを借りて文字列を効率的に照合または抽出できる process
モジュールの使用方法を学びます。
thefuzz
モジュールを使用して Python でファジー文字列を照合する
このライブラリは、名前が変更された特定の名前を持っていたため、古いバージョンではおかしな名前になっています。 そのため、現在は別のリポジトリが維持されています。 ただし、現在のバージョンは thefuzz
と呼ばれているため、以下のコマンドに従ってインストールできます。
pip install thefuzz
しかし、オンラインで例を見ると、古い名前 fuzzywuzzy
の例がいくつか見つかります。 そのため、もはや保守されておらず、時代遅れですが、その名前の例がいくつか見つかるかもしれません。
thefuzz ライブラリは python-Levenshtei をベースにしているため、このコマンドでインストールする必要があります。
pip install python-Levenshtein
また、インストール中に問題が発生した場合は、次のコマンドを使用できます。またエラーが発生した場合は、Google で検索して関連する解決策を見つけることができます。
pip install python-Levenshtein-wheels
正規表現の使用や 2つの文字列に沿った文字列の比較など、本質的にあいまいな一致文字列。 ファジー ロジックの場合、条件の真理値は 0
と 1
の間の実数になります。
したがって、基本的に、何かが True
または False
であると言う代わりに、0
から 1
の間の任意の値を与えるだけです。 これは、距離メトリックを使用して、距離と呼ばれる値の形式で 2つの文字列間の非類似度を計算することによって計算されます。
指定された文字列を使用して、何らかのアルゴリズムを使用して 2つの文字列間の距離を見つけます。 インストールプロセスが完了したら、fuzz
モジュールから fuzz
と process
をインポートする必要があります。
from thefuzz import fuzz, process
fuzz
を使用する前に、2つの文字列間の非類似性を手動でチェックします。
ST1 = "Just a test"
ST2 = "just a test"
print(ST1 == ST2)
print(ST1 != ST2)
ブール値を返しますが、あいまいな方法で、これらの文字列がどの程度類似しているかのパーセンタイルを取得します。
False
True
ファジー文字列マッチングにより、ファジーな方法でこれをより効率的かつ迅速に行うことができます。 2つの文字列を含む 1つの例があり、1つの文字列が大文字の J
と同じではない (上記のように) とします。
先に進んで、類似度のメトリックを提供する ratio()
関数を呼び出すと、100
中 91
というかなり高い比率が得られます。
from thefuzz import fuzz, process
print(fuzz.ratio(ST1, ST2))
出力:
91
文字列がより長くなる場合、たとえば、1つの文字を変更するだけでなく、まったく別の文字列を変更する場合、それが何を返すかを確認してください。
ST1 = "This is a test string for test"
ST2 = "There aresome test string for testing"
print(fuzz.ratio(ST1, ST2))
おそらくいくつかの類似点があるでしょうが、それはかなりの75
になるでしょう。 これは単純な比率であり、複雑なことは何もありません。
75
先に進んで、部分比率などを試すこともできます。 たとえば、スコアを決定したい 2つの文字列があるとします。
ST1 = "There are test"
ST2 = "There are test string for testing"
print(fuzz.partial_ratio(ST1, ST2))
partial_ratio()
を使用すると、これら 2つの文字列が同じ部分文字列 (There are test
) を持っているため、100% になります。
ST2
では、いくつかの異なる単語 (文字列) がありますが、部分的な比率または個々の部分を見ているので問題ではありませんが、単純な比率は同じようには機能しません。
100
似ているが順序が異なる文字列があるとします。 次に、別のメトリックを使用します。
CASE_1 = "This generation rules the nation"
CASE_2 = "Rules the nation This generation"
2つのケースは、そのフレーズの同じ意味の正確なテキストを持っていますが、ratio()
を使用するとかなり異なり、partial_ratio()
を使用すると異なります。
token_sort_ratio()
を実行すると、これは 100% になります。これは、基本的に正確な単語ですが、順序が異なるためです。 つまり、これが token_sort_ratio()
関数が個々のトークンを取得してソートするものであり、それらがどの順序で来るかは問題ではありません。
print(fuzz.ratio(CASE_1, CASE_2))
print(fuzz.partial_ratio(CASE_1, CASE_2))
print(fuzz.token_sort_ratio(CASE_1, CASE_2))
出力:
47
64
100
さて、ある単語を別の単語に変えると、ここで別の数になりますが、本質的には、これは比率です。 個々のトークンの順序は気にしません。
CASE_1 = "This generation rules the nation"
CASE_2 = "Rules the nation has This generation"
print(fuzz.ratio(CASE_1, CASE_2))
print(fuzz.partial_ratio(CASE_1, CASE_2))
print(fuzz.token_sort_ratio(CASE_1, CASE_2))
出力:
44
64
94
token_sort_ratio()
もより多くの単語が含まれているため異なりますが、token_set_ratio()
と呼ばれるものもあり、セットには各トークンが 1 回だけ含まれます。
したがって、発生頻度は問題ではありません。 文字列の例を見てみましょう。
CASE_1 = "This generation"
CASE_2 = "This This generation generation generation generation"
print(fuzz.ratio(CASE_1, CASE_2))
print(fuzz.partial_ratio(CASE_1, CASE_2))
print(fuzz.token_sort_ratio(CASE_1, CASE_2))
print(fuzz.token_set_ratio(CASE_1, CASE_2))
かなり低いスコアがいくつか見られますが、token_set_ratio()
関数を使用して 100% を得たのは、This
と generation
の 2つのトークンが両方の文字列に存在するためです。
process
モジュールを使用してファジー文字列一致を効率的に使用する
fuzz
だけでなく process
もあります。これは、process
が役に立ち、このファジー マッチングを使用してコレクションから抽出できるためです。
たとえば、デモ用にいくつかのリスト項目を用意しました。
Diff_items = [
"programing language",
"Native language",
"React language",
"People stuff",
"This generation",
"Coding and stuff",
]
それらのいくつかはかなり似ています (母国語またはプログラミング言語) を見ることができます。そして今、先に進んで個々の最適な一致を選択できます。
スコアを評価して上位のピックを選択するだけで手動で行うことができますが、プロセス
を使用して行うこともできます。 そのためには、process
モジュールから extract()
関数を呼び出す必要があります。
いくつかのパラメーターが必要です。1つ目は対象の文字列、2つ目は抽出するコレクション、3つ目は一致または抽出を 2つに制限する制限です。
たとえば、language
のようなものを抽出したい場合、この場合、母国語とプログラミング言語が選択されました。
print(process.extract("language", Diff_items, limit=2))
出力:
[('programing language', 90), ('Native language', 90)]
問題は、これが NLP (自然言語処理) ではないことです。 この背後に知性はありません。 個々のトークンを見るだけです。 たとえば、programming
をターゲット文字列として使用し、これを実行するとします。
1回目はプログラミング言語
ですが、2回目はコーディングではないネイティブ言語
になります。
セマンティクスからコーディングはプログラミングに近いため、コーディングがありますが、ここでは AI を使用していないため、それは問題ではありません。
Diff_items = [
"programing language",
"Native language",
"React language",
"People stuff",
"Hello World",
"Coding and stuff",
]
print(process.extract("programing", Diff_items, limit=2))
出力:
[('programing language', 90), ('Native language', 36)]
もう 1つの最後の例は、これがどのように役立つかです。 私たちは本の膨大な図書館を持っていて、本を見つけたいと思っていますが、正確な名前や呼び方がわかりません。
この場合、extract()
を使用でき、この関数内で fuzz.token_sort_ratio
を scorer
引数に渡します。
LISt_OF_Books = [
"The python everyone volume 1 - Beginner",
"The python everyone volume 2 - Machine Learning",
"The python everyone volume 3 - Data Science",
"The python everyone volume 4 - Finance",
"The python everyone volume 5 - Neural Network",
"The python everyone volume 6 - Computer Vision",
"Different Data Science book",
"Java everyone beginner book",
"python everyone Algorithms and Data Structure",
]
print(
process.extract(
"python Data Science", LISt_OF_Books, limit=3, scorer=fuzz.token_sort_ratio
)
)
私たちはそれを通過しているだけです。 私たちはそれを呼んでいません。今、ここで最高の結果を得て、2 番目の結果として別のデータ サイエンスの本を手に入れました。
出力:
[('The python everyone volume 3 - Data Science', 63), ('Different Data Science book', 61), ('python everyone Algorithms and Data Structure', 47)]
これは非常に正確な方法であり、あいまいな方法で検索する必要があるプロジェクトがある場合に非常に役立ちます。 また、これを使用して手順を自動化することもできます。
github と stackoverflow を使用して詳細なヘルプを見つけることができる追加のリソースがあります。
Hello! I am Salman Bin Mehmood(Baum), a software developer and I help organizations, address complex problems. My expertise lies within back-end, data science and machine learning. I am a lifelong learner, currently working on metaverse, and enrolled in a course building an AI application with python. I love solving problems and developing bug-free software for people. I write content related to python and hot Technologies.
LinkedIn