Pythonでgensimのword2vecモデルを使用して文の類似性を計算する方法


125

による Gensim Word2Vecに gensimパッケージのword2vecモデルを使用して、2つの単語間の類似度を計算できます。

例えば

trained_model.similarity('woman', 'man') 
0.73723527

ただし、word2vecモデルは文の類似性を予測できません。gensimで文の類似性を持つLSIモデルを見つけましたが、word2vecモデルと組み合わせることができないようです。私が持っている各文のコーパスの長さはあまり長くありません(10語より短い)。それで、目標を達成する簡単な方法はありますか?


4
この問題を説明するACLチュートリアルがあります(とりわけ):youtube.com/watch
v

7
これで、gensimのdoc2vecを使用して、同じモジュールから文の類似性を取得できます
kampta

@kampta。こんにちは、実装を示す投稿を提案しますか?
Ian_De_Oliveira 2018

回答:


86

これは実際、あなたが求めているかなり難しい問題です。文の類似性を計算するには、文の文法モデルを構築し、同等の構造(たとえば、「昨日は店に歩いた」と「昨日、店に歩いた」)を理解し、代名詞や動詞だけでなく、固有名詞、多くの実際のテキスト例における統計的共起/関係の発見など。

あなたが試すことができる最も簡単なこと-これがどれだけうまく機能するかはわかりませんが、確かに最適な結果は得られません-は、最初にすべての「ストップ」ワード(「the」、「an "など、文にあまり意味がありません)。次に、両方の文の単語に対してword2vecを実行し、1つの文のベクトルを合計し、他の文のベクトルを合計してから、合計。単語ごとの違いを行う代わりにそれらを合計することにより、少なくとも単語の順序の影響を受けなくなります。そうは言っても、これは多くの点で失敗し、どのような方法でも適切な解決策ではありません(この問題に対する適切な解決策には、ほとんどの場合、ある程度の量のNLP、機械学習、およびその他の巧妙さが含まれます)。

つまり、簡単な答えは、いいえ、これを行う簡単な方法はないということです(少なくともうまく実行することはできません)。


4
私はあなたが正しいと思います。最も簡単な方法は、1つの文に単語のすべてのベクトルを累積し、和の差を見つけることです。ところで、この簡単な方法は単語数の影響を受けますか?1つの文の単語数が多いほど、より多くのヒストグラムが合計されます。
zhfkt 2014

2
@zhfkt、おそらくそうです。したがって、それを分解するために、単語数などで除算する必要がある場合があります。どちらにしても、このようなヒューリスティックには重大な欠陥があります。
Michael Aaron Safyan 2014年


75

gensimを使用しているため、おそらくdoc2vec実装を使用する必要があります。doc2vecは、word2vecをフレーズレベル、文レベル、およびドキュメントレベルに拡張したものです。これは非常に単純な拡張です。ここで説明します

http://cs.stanford.edu/~quocle/paragraph_vector.pdf

Gensimは直感的で、高速で、柔軟性があるため優れています。すばらしいのは、公式のword2vecページから事前トレーニング済みの単語の埋め込みを取得でき、gensimのDoc2Vecモデルのsyn0レイヤーが公開されているので、これらの高品質のベクターで単語の埋め込みをシードできることです。

GoogleNews-vectors-negative300.bin.gzGoogle Codeにリンクされています

gensimは、文をベクトル空間に埋め込むための最も簡単な(そして今のところ私にとっては最高の)ツールだと思います。

上記のLe&Mikolovの論文で提案されたもの以外に、他の文章からベクトルへのテクニックが存在します。スタンフォードのソッチャーとマニングは、確かにこの分野で働いている最も有名な研究者の2人です。彼らの作品は作文の原則に基づいています-文の意味論は以下から来ています:

1. semantics of the words

2. rules for how these words interact and combine into phrases

彼らは、構成レベルを使用して文レベルの表現を構築する方法について、いくつかのそのようなモデル(ますます複雑になる)を提案しました。

2011- 再帰オートエンコーダの展開(非常に単純です。興味があればここから始めてください)

2012- 行列-ベクトルニューラルネットワーク

2013- ニューラルテンソルネットワーク

2015- ツリーLSTM

彼の論文はすべてsocher.orgで入手できます。これらのモデルのいくつかは利用可能ですが、私はまだgensimのdoc2vecをお勧めします。まず、2011 URAEはそれほど強力ではありません。さらに、news-yデータの言い換えに適した重みがあらかじめトレーニングされています。彼が提供するコードでは、ネットワークを再トレーニングすることはできません。また、異なるワードベクトルを入れ替えることもできないため、Turianからの2011年のpre-word2vec埋め込みで立ち往生しています。これらのベクトルは、word2vecやGloVeのレベルにはありません。

Tree LSTMはまだ使用していませんが、非常に有望です。

tl; drええ、gensimのdoc2vecを使用してください。しかし、他の方法が存在します!


事前にトレーニングされたword2vec値でdoc2vecモデルを初期化する方法に関する詳細情報はありますか?
Simon H

42

word2vecを使用している場合は、すべての文/ドキュメント内のすべての単語の平均ベクトルを計算し、ベクトル間のコサイン類似度を使用する必要があります。

import numpy as np
from scipy import spatial

index2word_set = set(model.wv.index2word)

def avg_feature_vector(sentence, model, num_features, index2word_set):
    words = sentence.split()
    feature_vec = np.zeros((num_features, ), dtype='float32')
    n_words = 0
    for word in words:
        if word in index2word_set:
            n_words += 1
            feature_vec = np.add(feature_vec, model[word])
    if (n_words > 0):
        feature_vec = np.divide(feature_vec, n_words)
    return feature_vec

類似度を計算します。

s1_afv = avg_feature_vector('this is a sentence', model=model, num_features=300, index2word_set=index2word_set)
s2_afv = avg_feature_vector('this is also sentence', model=model, num_features=300, index2word_set=index2word_set)
sim = 1 - spatial.distance.cosine(s1_afv, s2_afv)
print(sim)

> 0.915479828613

4
index2word_setとmodel.index2wordについて詳しく説明してもらえますか?ありがとうございました。
theteddyboy 2017

3
「平均ベクトル」を計算することは、まったく計算しないことと同じくらい多くの任意の選択であることに注意してください。
2017

2
これが最高の答えではない理由に驚いています。これは非常にうまく機能し、平均化方法のようなシーケンスの問題はありません。
Asim

これは私が探していた答えです。私の問題を解決しました。ソリューションをありがとう
iRunner

25

Word Moverの距離アルゴリズムを使用できます。ここでWMDに関する簡単な説明が

#load word2vec model, here GoogleNews is used
model = gensim.models.KeyedVectors.load_word2vec_format('../GoogleNews-vectors-negative300.bin', binary=True)
#two sample sentences 
s1 = 'the first sentence'
s2 = 'the second text'

#calculate distance between two sentences using WMD algorithm
distance = model.wmdistance(s1, s2)

print ('distance = %.3f' % distance)

Ps:pyemdライブラリのインポートに関するエラーが発生した場合は、次のコマンドを使用してインストールできます。

pip install pyemd

2
以前WMDを使用しましたが、静かに動作しますが、大きなコーパスでは窒息します。SoftCosineSimilarityを試してください。またgensim(に見出さtwitter.com/gensim_py/status/963382840934195200
krinker

1
WMDは非常に高速ではありませんが、コーパスを照会する場合はそうです。
Amartya

18

2組の単語ベクトルの合計を計算したら、diffではなく、ベクトル間のコサインを取る必要があります。コサインは、正規化された2つのベクトルの内積をとることによって計算できます。したがって、単語数は要素ではありません。


1
これを行う方法について少し疑似コードを提供できますか(私はgensim / pythonを使用していません)
dcsan

13

ドキュメンテーションには、単語のリストを取り、それらの類似点を比較する機能があります。

s1 = 'This room is dirty'
s2 = 'dirty and disgusting room' #corrected variable name

distance = model.wv.n_similarity(s1.lower().split(), s2.lower().split())

12

既存のソリューションを更新して、文の意味的類似度を計算しようとしている人々を支援したいと思います。

ステップ1:

gensimを使用して適切なモデルを読み込み、文の単語の単語ベクトルを計算して、単語リストとして保存します。

ステップ2:文のベクトルを計算する

文章間の意味的類似性の計算は以前は困難でしたが、最近、「文章埋め込みのシンプルで強靭なベースライン」という名前の論文が提案されました。最初の主成分の平均ベクトルの射影ここで、単語wの重みはa /(a + p(w))であり、aはパラメータであり、p(w)は滑らかな逆周波数と呼ばれる(推定)単語の周波数です。この方法はパフォーマンスが大幅に向上します。

SIF(スムーズインバース周波数)を使用して文章ベクトルを計算する簡単なコードは、論文で提案された方法がここに与えられています

ステップ3:sklearn cosine_similarityを使用して、文の2つのベクトルを読み込み、類似度を計算します。

これは、文の類似度を計算する最も簡単で効率的な方法です。


2
とても素敵な紙。注:SIF実装へのリンクには、PythonのCounter()を使用してdictを返すことで簡単に実行できるget_word_frequency()メソッドを記述する必要があります。一意の単語w、値:#w /#total doc len
Quetzalcoatl

8

私は次の方法を使用していますが、うまくいきます。最初にPOSTaggerを実行してから、ストップワード(行列式、接続詞など)を取り除くために文をフィルタリングする必要があります。TextBlob APTaggerをお勧めします。次に、文の各単語ベクトルの平均を取ることによってword2vecを作成します。Gemsim word2vecでn_similarity方法比較する単語の二組を通過させることによって、その正確ありません。


ベクトルの平均を取ることと、それらを追加して文ベクトルを作成することの違いは何ですか?
Καrτhικ

1
違いは、すべての文のベクトルサイズが固定されていることです
lechatpito

コサイン類似度を使用している限り、違いはありません。@lechatpitoベクトルサイズとは関係ありません。ベクトルは連結されずに合計されます。
ウォック

6

Word2Vecの拡張機能には、フレーズや文などの長いテキストを比較する問題を解決するためのものがあります。それらの1つは、paragraph2vecまたはdoc2vecです。

「文とドキュメントの分散表示」 http://cs.stanford.edu/~quocle/paragraph_vector.pdf

http://rare-technologies.com/doc2vec-tutorial/


2
提示されたアルゴリズムがどのように機能するかについては、すぐに言及する価値があります。基本的に、すべての発話に一意の「トークン」を追加し、word2vecベクトルを計算します。最後に、コーパス内の各単語の単語ベクトルを取得します(すべての単語と一意の単語も要求した場合)。発話内の一意の「トークン」はそれぞれ、その発話を表します。論文で提示された結果についてはいくつかの論争がありますが、それは別の話です。
Vladislavs Dovgalecs 2016年

5

Gensim道具というモデルDoc2Vecのための段落の埋め込み

IPythonノートブックとして提示されているさまざまなチュートリアルがあります。

このチュートリアルに示すように、別の方法はWord2VecWord Moverの距離(WMD)に依存します

別の解決策は、平均ベクトルに依存することです:

from gensim.models import KeyedVectors
from gensim.utils import simple_preprocess    

def tidy_sentence(sentence, vocabulary):
    return [word for word in simple_preprocess(sentence) if word in vocabulary]    

def compute_sentence_similarity(sentence_1, sentence_2, model_wv):
    vocabulary = set(model_wv.index2word)    
    tokens_1 = tidy_sentence(sentence_1, vocabulary)    
    tokens_2 = tidy_sentence(sentence_2, vocabulary)    
    return model_wv.n_similarity(tokens_1, tokens_2)

wv = KeyedVectors.load('model.wv', mmap='r')
sim = compute_sentence_similarity('this is a sentence', 'this is also a sentence', wv)
print(sim)

最後に、Tensorflowを実行できる場合は、https://tfhub.dev/google/universal-sentence-encoder/2を試すことができ ます。


4

以前の回答で提供された方法を試しました。それは機能しますが、主な欠点は、文が長くなるほど類似性が大きくなることです(類似性を計算するには、2つの文の2つの平均埋め込みのコサインスコアを使用します)。文に追加されます。

この論文これで学習したように、気が変わって代わりに埋め込みの文を使用するべきだと思いました。


3

Facebook ResearchグループがInferSent Resultsと呼ばれる新しいソリューションをリリースし、コードがGithubに公開されています。リポジトリを確認してください。それはかなり素晴らしいです。使うつもりです。 https://github.com/facebookresearch/InferSent

彼らの論文 https://arxiv.org/abs/1705.02364 要約:最近の多くのNLPシステムは、以前は教師なしの方法で大規模なコーパスに対してトレーニングされた単語の埋め込みを基本機能として使用しています。しかし、文章などのより大きなテキストのチャンクの埋め込みを取得する取り組みは、それほど成功していません。教師なしの文の表現を学習するいくつかの試みは、広く採用されるのに十分な性能に達していません。このホワイトペーパーでは、スタンフォード自然言語推論データセットの教師ありデータを使用してトレーニングされた普遍的な文の表現が、SkipThoughtベクトルのような教師なしメソッドよりも広範囲の転送タスクで一貫して優れたパフォーマンスを発揮できることを示します。コンピュータービジョンがImageNetを使用して機能を取得する方法と同様に、他のタスクに転送できます。私たちの仕事は、自然言語推論が他のNLPタスクへの転移学習に適していることを示す傾向があります。エンコーダーは公開されています。


3

Word2Vecを使用していない場合は、BERTを使用して埋め込む他のモデルがあります。以下は参照リンクです https://github.com/UKPLab/sentence-transformers

pip install -U sentence-transformers

from sentence_transformers import SentenceTransformer
import scipy.spatial

embedder = SentenceTransformer('bert-base-nli-mean-tokens')

# Corpus with example sentences
corpus = ['A man is eating a food.',
          'A man is eating a piece of bread.',
          'The girl is carrying a baby.',
          'A man is riding a horse.',
          'A woman is playing violin.',
          'Two men pushed carts through the woods.',
          'A man is riding a white horse on an enclosed ground.',
          'A monkey is playing drums.',
          'A cheetah is running behind its prey.'
          ]
corpus_embeddings = embedder.encode(corpus)

# Query sentences:
queries = ['A man is eating pasta.', 'Someone in a gorilla costume is playing a set of drums.', 'A cheetah chases prey on across a field.']
query_embeddings = embedder.encode(queries)

# Find the closest 5 sentences of the corpus for each query sentence based on cosine similarity
closest_n = 5
for query, query_embedding in zip(queries, query_embeddings):
    distances = scipy.spatial.distance.cdist([query_embedding], corpus_embeddings, "cosine")[0]

    results = zip(range(len(distances)), distances)
    results = sorted(results, key=lambda x: x[1])

    print("\n\n======================\n\n")
    print("Query:", query)
    print("\nTop 5 most similar sentences in corpus:")

    for idx, distance in results[0:closest_n]:
        print(corpus[idx].strip(), "(Score: %.4f)" % (1-distance))

フォローする他のリンク https://github.com/hanxiao/bert-as-service

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