Python
gensim
doc2vec

[gensim]Doc2Vecの使い方

大抵はgensimの公式に書いてあるけど、日本語の資料はそんなに多くないので、自分がよく使う基本的なやつを初心者向けにまとめときます。

準備(インストール)

pip install gensim

学習データの形成

サイトによって書き方違うんですが、個人的にはこの書き方で落ち着いてます

#coding: UTF-8
from gensim.models.doc2vec import Doc2Vec
from gensim.models.doc2vec import TaggedDocument

f = open('学習データ.txt','r')#空白で単語を区切り、改行で文書を区切っているテキストデータ

#1文書ずつ、単語に分割してリストに入れていく[([単語1,単語2,単語3],文書id),...]こんなイメージ
#words:文書に含まれる単語のリスト(単語の重複あり)
# tags:文書の識別子(リストで指定.1つの文書に複数のタグを付与できる)
trainings = [TaggedDocument(words = data.split(),tags = [i]) for i,data in enumerate(f)]

ちなみに今回学習したのは、読書メーターのレビュー1200万件のデータです。こそこそとスクレイピングで収集しました。1GB超えてるので、メモリに乗っけるのもPCによってはなかなか大変

モデルの学習

# トレーニング(パラメータについては後日)
m = Doc2Vec(documents= trainings, dm = 1, size=300, window=8, min_count=10, workers=4)

# モデルのセーブ
m.save("model/doc2vec.model")

# モデルのロード(モデルが用意してあれば、ここからで良い)
m = Doc2Vec.load('model/doc2vec2.model')

学習データのサイズによってはかなり時間かかるので注意

よく使う機能

学習文書の中で、指定したidの文書と類似度の高い文書を調べる

#引数は文書id
print m.docvecs.most_similar(0)

#文書0と類似している上位10件の文書idと類似度のセットが返ってくる
>> [(55893, 0.6868613362312317), (85550, 0.6866280436515808), (80831, 0.6864551305770874), (61463, 0.6863148212432861), (72602, 0.6847503185272217), (56876, 0.6835699081420898), (80847, 0.6832736134529114), (92838, 0.6829516291618347), (24495, 0.6820268630981445), (45589, 0.679581880569458)]

任意の文書間の類似度を調べる

print m.docvecs.similarity(1,307)
#文書1と文書307の間の類似度
>> 0.279532733106

学習したモデルを使って、新規に与えた文書の同士の類似度を調べる

#例えば、以下の4つの新規文書の、いくつかの組み合わせの類似度を計算してみる
doc_words1 = ["ラスト", "展開" ,"早い" ,"他" ,"作品", "衝撃", "受ける" ,"裏の裏" ,"つく", "トリック" ,"毎度" ,"こと", "脱帽", "する", "読む", "やすい" ,"め" ,"ミステリー"]
doc_words2 = [ "イニシエーション・ラブ", "同様" ,"最後", "数行", "どんでん返し", "いく", "時", "時", "様々", "シーン", "する" ,"れる", "伏線" ,"散りばめる", "られる" ,"いる", "こと", "気づく"]
doc_words3 = ["ラスト", "展開" ,"早い" ,"他" ,"作品", "衝撃", "受ける" ,"裏の裏" ,"つく","ミステリー"]
doc_words4 = ["独特", "世界観", "日常" ,"離れる","落ち着く","時","読む","本"]

print "1-2 sim"
sim_value = m.docvecs.similarity_unseen_docs(m, doc_words1, doc_words2, alpha=1, min_alpha=0.0001, steps=5)
print sim_value

print "1-3 sim"
print m.docvecs.similarity_unseen_docs(m, doc_words1, doc_words3, alpha=1, min_alpha=0.0001, steps=5)

print "1-4 sim"
print m.docvecs.similarity_unseen_docs(m, doc_words1, doc_words4, alpha=1, min_alpha=0.0001, steps=5)

print "2-3 sim"
print m.docvecs.similarity_unseen_docs(m, doc_words2, doc_words3, alpha=1, min_alpha=0.0001, steps=5)

>> 1-2 sim
   0.10429317017
   1-3 sim
   0.472984922936
   1-4 sim
   -0.02320307339
   2-3 sim
   0.228117846023

人が見ても、文書1-3とか2-3は似てるし、逆に文書1-4は似てないのは明らかなので、なかなか良い感じに類似度が出てます

新規文書の圧縮ベクトルを出力(学習するときにsizeで指定した次元数のベクトルで出力される)

newvec = m.infer_vector(doc_words1)

print newvec

>> [  1.19107231e-01  -4.06390838e-02  -2.55129002e-02   1.16982162e-01
  -1.47758834e-02   1.07912444e-01  -4.76960577e-02  -9.73785818e-02
   #...(中略)
  -1.61364377e-02  -9.76370368e-03   4.98018935e-02  -8.88026431e-02
   1.34409174e-01  -1.01136886e-01  -4.24979888e-02   7.16169327e-02]

今後追加したいこと

  • モデルを学習する際のパラメータの調整
  • どんなことに応用できるか

あと、doc2vecのアルゴリズム自体に関して
工学院大学の北山研のブログで説明している記事を見つけました
doc2vec(Paragraph Vector) のアルゴリズム