web-dev-qa-db-ja.com

ファジー文字列の比較

私が完了しようとしているのは、ファイルを読み込み、元の文に従って各文を比較するプログラムです。オリジナルと完全に一致する文はスコア1を受け取り、反対側の合計文は0を受け取ります。他のすべてのファジー文は1〜0の評点を受け取ります。

これをPython 3。

テキスト1が元で、他の先行する文字列が比較であるサンプルテキストを含めました。

テキスト:サンプル

テキスト1:暗い嵐の夜でした。私は一人で赤い椅子に座っていました。私は3匹の猫を飼っていたので、完全に一人ではありませんでした。

テキスト20:暗くて嵐の夜でした。私は一人で深紅色の椅子に座っていました。 3匹のネコがいたので、私は完全に一人ではありませんでした

テキスト21:暗くて激しい夜でした。私は一人で深紅のカテドラに座っていました。 3匹のネコがいたので、私は完全に一人ではありませんでした

テキスト22:私は一人で深紅のカテドラに座っていました。 3匹のネコがいたので、私は完全に一人ではありませんでした。暗くて激しい夜でした。 //テキストは21より低いが、0はない

テキスト24:暗い嵐の夜でした。私は一人ではありませんでした。私は赤い椅子に座っていませんでした。私は3匹の猫を飼っていました。 // 0を記録する必要があります!

57
jacksonstephenc

fuzzywuzzy というパッケージがあります。 pipを使用してインストールします。

pip install fuzzywuzzy

簡単な使用法:

>>> from fuzzywuzzy import fuzz
>>> fuzz.ratio("this is a test", "this is a test!")
    96

パッケージはdifflibの上に構築されます。なぜそれを使用しないのですか?少しシンプルであるだけでなく、実際にはより強力なさまざまなマッチング方法(トークンの順序に依存しない、部分的な文字列のマッチングなど)があります。 process.extract関数は特に便利です。セットから最適な文字列と比率を見つけます。彼らのreadmeから:

部分比率

>>> fuzz.partial_ratio("this is a test", "this is a test!")
    100

トークンのソート率

>>> fuzz.ratio("fuzzy wuzzy was a bear", "wuzzy fuzzy was a bear")
    90
>>> fuzz.token_sort_ratio("fuzzy wuzzy was a bear", "wuzzy fuzzy was a bear")
    100

トークンセット比率

>>> fuzz.token_sort_ratio("fuzzy was a bear", "fuzzy fuzzy was a bear")
    84
>>> fuzz.token_set_ratio("fuzzy was a bear", "fuzzy fuzzy was a bear")
    100

処理する

>>> choices = ["Atlanta Falcons", "New York Jets", "New York Giants", "Dallas Cowboys"]
>>> process.extract("new york jets", choices, limit=2)
    [('New York Jets', 100), ('New York Giants', 78)]
>>> process.extractOne("cowboys", choices)
    ("Dallas Cowboys", 90)
96
congusbongus

標準ライブラリには、文字列を比較し、類似性に基づいてスコアを返すことができるモジュール( difflib と呼ばれます)があります。 SequenceMatcher クラスは、あなたが望んでいることをするべきです。

EDIT:pythonプロンプト:

>>> from difflib import SequenceMatcher as SM
>>> s1 = ' It was a dark and stormy night. I was all alone sitting on a red chair. I was not completely alone as I had three cats.'
>>> s2 = ' It was a murky and stormy night. I was all alone sitting on a crimson chair. I was not completely alone as I had three felines.'
>>> SM(None, s1, s2).ratio()
0.9112903225806451

HTH!

78
mac

fuzzyset は、インデックス作成と検索の両方でfuzzywuzzydifflib)よりもはるかに高速です。

from fuzzyset import FuzzySet
corpus = """It was a murky and stormy night. I was all alone sitting on a crimson chair. I was not completely alone as I had three felines
    It was a murky and tempestuous night. I was all alone sitting on a crimson cathedra. I was not completely alone as I had three felines
    I was all alone sitting on a crimson cathedra. I was not completely alone as I had three felines. It was a murky and tempestuous night.
    It was a dark and stormy night. I was not alone. I was not sitting on a red chair. I had three cats."""
corpus = [line.lstrip() for line in corpus.split("\n")]
fs = FuzzySet(corpus)
query = "It was a dark and stormy night. I was all alone sitting on a red chair. I was not completely alone as I had three cats."
fs.get(query)
# [(0.873015873015873, 'It was a murky and stormy night. I was all alone sitting on a crimson chair. I was not completely alone as I had three felines')]

警告:ファジーセットにunicodebytesを混在させないように注意してください。

14
hobs

このタスクは Paraphrase Identification と呼ばれ、自然言語処理の研究の活発な分野です。 GitHubでオープンソースコードを見つけることができる最新の論文をいくつかリンクしています。

答えられた質問はすべて、2つの文の間に文字列/表面の類似性があると仮定しているのに対し、実際には文字列の類似性がほとんどない2つの文は意味的に類似していることに注意してください。

そのような類似性に興味がある場合は、 Skip-Thoughts を使用できます。 GitHubガイドに従ってソフトウェアをインストールし、readmeの言い換え検出セクションに移動します。

import skipthoughts
model = skipthoughts.load_model()
vectors = skipthoughts.encode(model, X_sentences)

これにより、文章(X_sentences)がベクトルに変換されます。後で、次の方法で2つのベクトルの類似性を見つけることができます。

similarity = 1 - scipy.spatial.distance.cosine(vectors[0], vectors[1])

ここで、vector [0]とvector 1 は、X_sentences [0]、X_sentences 1 に対応するベクトルであり、スコアを求めたいと仮定しています。

文をベクトルに変換する他のモデルがあり、それを こちら で見つけることができます。

文章をベクトルに変換すると、類似性は、それらのベクトル間のコサイン類似性を見つけるだけの問題です。

1
Ash