文の類似性予測


15

私は次の問題を解決しようとしています:データセットとして一連の文があり、新しい文を入力して、新しい文がデータセット内で最も類似している文を見つけたいです。例は次のようになります。

新しい文:「I opened a new mailbox

データセットに基づいた予測:

Sentence                       | Similarity
A dog ate poop                   0%
A mailbox is good                50%
A mailbox was opened by me       80%

コサインの類似性は、tf-idfと組み合わせたこれらの種類の問題を解決するために使用できることを読みました(およびRNNは基本的な方法に大きな改善をもたらすべきではありません)、またはword2vecも同様の問題に使用されます。これらもこの特定のケースで実際に使用可能ですか?これを解決する他のテクニック/アルゴリズムはありますか(できればPythonとSKLearnを使用しますが、TensorFlowについても学ぶことができます)?


間違いなくBertを確認してください。これは素晴らしい実装です。探しているものとまったく同じ結果が得られ、かなり良い結果が得られます
GioGio

回答:


25

問題はWord2vecとDoc2vecで解決できます。Doc2vecは、モデルのトレーニング中にセンテンスを考慮するため、より良い結果が得られます。

Doc2vecソリューション
このリンクに従ってdoc2vecモデルをトレーニングできます。すべてのストップワード(「the」、「an」など、文にあまり意味を加えない単語)を削除するなど、いくつかの前処理ステップを実行することができます。モデルをトレーニングしたら、次のコードを使用して同様の文を見つけることができます。

import gensim  

model = gensim.models.Doc2Vec.load('saved_doc2vec_model')  

new_sentence = "I opened a new mailbox".split(" ")  
model.docvecs.most_similar(positive=[model.infer_vector(new_sentence)],topn=5)

結果:

[('TRAIN_29670', 0.6352514028549194),
 ('TRAIN_678', 0.6344441771507263),
 ('TRAIN_12792', 0.6202734708786011),
 ('TRAIN_12062', 0.6163255572319031),
 ('TRAIN_9710', 0.6056315898895264)]

上記の結果は、のタプルのリストです(label,cosine_similarity_score)。を実行することにより、出力をセンテンスにマッピングできますtrain[29670]

上記のアプローチは、doc2vecモデルに新しい文で見つかった単語の埋め込みが含まれている場合にのみ良い結果が得られることに注意してください。のようなsdsf sdf f sdf sdfsdffg意味不明な文の類似性を取得しようとすると、結果はほとんど得られませんが、訓練されたモデルはモデルの訓練中にこれらの意味不明な単語を見なかったため、実際の類似した文ではない場合があります。そのため、より良い結果を得るためにできるだけ多くの単語を組み込むために、できるだけ多くの文でモデルをトレーニングしてみてください。

Word2vecソリューションword2vec
を使用している場合、すべての文のすべての単語の平均ベクトルを計算し、ベクトル間のコサイン類似度を使用する必要があります。

def avg_sentence_vector(words, model, num_features, index2word_set):
    #function to average all words vectors in a given paragraph
    featureVec = np.zeros((num_features,), dtype="float32")
    nwords = 0

    for word in words:
        if word in index2word_set:
            nwords = nwords+1
            featureVec = np.add(featureVec, model[word])

    if nwords>0:
        featureVec = np.divide(featureVec, nwords)
    return featureVec

類似度を計算する

#get average vector for sentence 1
sentence_1 = "this is sentence number one"
sentence_1_avg_vector = avg_sentence_vector(sentence_1.split(), model=word2vec_model, num_features=100)

#get average vector for sentence 2
sentence_2 = "this is sentence number two"
sentence_2_avg_vector = avg_sentence_vector(sentence_2.split(), model=word2vec_model, num_features=100)

sen1_sen2_similarity =  cosine_similarity(sentence_1_avg_vector,sentence_2_avg_vector)

ありがとうございました!週末にこれで動作しますが、ソリューションは一見完璧に見えます。称賛!
lte__

トレーニングのために文章をトークン化する必要がありますか
-pyd

はい@pydする必要があります!sentence_1.split()同じことをします。
ハーマン

4

ワードムーバーの距離(WMD)は、文間の距離を見つけるためのアルゴリズムです。WMDは、語の意味的意味を密なベクトルにエンコードする語の埋め込み(word2vecなど)に基づいています。

WMD距離は、2つのテキストドキュメント間の相違を、あるドキュメントの埋め込み単語が別のドキュメントの埋め込み単語に到達するために「移動」する必要がある最小距離として測定します。

例えば:

ここに画像の説明を入力してください 出典:「Wordの埋め込みからドキュメントの距離まで」ペーパー

gensimパッケージがありWMDの実装を

問題については、入力された文を他のすべての文と比較し、WMDが最も低い文を返します。


2

sklearnを使用して簡単な解決策を試すことができますが、うまくいくでしょう。

  • tfidfvectorizerを使用して、各テキストのベクトル表現を取得します

  • ベクトライザーをデータに合わせて、ストップワードを削除します

  • 以前にトレーニングしたベクトライザーで新しいエントリを変換します

  • この表現とデータセット内の要素の各表現の間の余弦類似度を計算します。

ヒューデータセットがある場合、表現を取得した後、新しいデータを予測する前に、(たとえばscikit learnのKMeansを使用して)クラスター化できます。

このコードはこれらすべてのステップを実行します。私のgithub リポジトリで確認できます。

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
from sklearn.metrics import adjusted_rand_score
import numpy

texts = ["This first text talks about houses and dogs",
        "This is about airplanes and airlines",
        "This is about dogs and houses too, but also about trees",
        "Trees and dogs are main characters in this story",
        "This story is about batman and superman fighting each other", 
        "Nothing better than another story talking about airplanes, airlines and birds",
        "Superman defeats batman in the last round"]

# vectorization of the texts
vectorizer = TfidfVectorizer(stop_words="english")
X = vectorizer.fit_transform(texts)
# used words (axis in our multi-dimensional space)
words = vectorizer.get_feature_names()
print("words", words)


n_clusters=3
number_of_seeds_to_try=10
max_iter = 300
number_of_process=2 # seads are distributed
model = KMeans(n_clusters=n_clusters, max_iter=max_iter, n_init=number_of_seeds_to_try, n_jobs=number_of_process).fit(X)

labels = model.labels_
# indices of preferible words in each cluster
ordered_words = model.cluster_centers_.argsort()[:, ::-1]

print("centers:", model.cluster_centers_)
print("labels", labels)
print("intertia:", model.inertia_)

texts_per_cluster = numpy.zeros(n_clusters)
for i_cluster in range(n_clusters):
    for label in labels:
        if label==i_cluster:
            texts_per_cluster[i_cluster] +=1 

print("Top words per cluster:")
for i_cluster in range(n_clusters):
    print("Cluster:", i_cluster, "texts:", int(texts_per_cluster[i_cluster])),
    for term in ordered_words[i_cluster, :10]:
        print("\t"+words[term])

print("\n")
print("Prediction")

text_to_predict = "Why batman was defeated  by superman so easy?"
Y = vectorizer.transform([text_to_predict])
predicted_cluster = model.predict(Y)[0]
texts_per_cluster[predicted_cluster]+=1

print(text_to_predict)
print("Cluster:", predicted_cluster, "texts:", int(texts_per_cluster[predicted_cluster])),
for term in ordered_words[predicted_cluster, :10]:
print("\t"+words[term])

ちょっと、コサインの類似性を使用した例を示すことができたら、本当にいいでしょうか?
ティド

ちょっと、パート2が最初に来て、すべてのデータに適合し、これを使用して各テキストを変換するべきではないでしょうか?余弦の類似性を使用した例を示すことができれば、本当に素晴らしいでしょうか?
ティド

1

RNNモデルにはVariation Auto-Encoderに基づいた最近の研究がいくつかあります。連続空間から文章の生成:pytorch実装で、githubのコード
彼らは、文の意味的で構文的な大域的特徴を、おそらく有限の10から30の独立したランダム変数で表現された潜在空間に圧縮することができました(因数分解)。
この作品の斬新なアイデアは、2つの文の間を補間します。その結果は非常に素晴らしいものでした。


0

一般化されたソリューションは、次の手順で構成されます-

  1. 文の特徴化または単語の埋め込み。
  2. 文間の類似性メトリックの適用。

nバツnnバツdd

各単語の単語の埋め込みを取得したら、コサイン類似性などの類似性メトリックを各文に適用して、他の文との類似性を測定できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.