Skip to content

トピックモデルで単語の分散表現 – 実装編

前回の記事 トピックモデルで単語の分散表現 – 理論編 では、トピックモデル・LDAの基本構造とアイディアを説明したが、今回はPythonで実際にトピックモデルを使って単語の分散(ベクトル)表現を作ってみる。

 

トピックモデルライブラリgensim

今回はフルスクラッチではなく、LDAやLSAやword2vecが簡単に使えるpython用ライブラリgensimを利用する。gensimをインストール後、

from gensim.models.ldamodel import LdaModel

でgensimのLDAModelをimportする。

以下の関数は、単語の共起表現ベクトルのリストvectorsを受け、gensimの関数LdaModelを用いてLDAモデルを学習(これにはデータサイズに依るが数十分時間がかかる)し、指定したmodel_nameでモデルを保存する関数である。

def lda(vectors, wordMapping, model_name=LDA_MODEL_PATH):

    # Convert to sparse vectors
    sparse_vectors = [convert_to_sparse(vector) for vector in vectors]

    trained_model = LdaModel(sparse_vectors, num_topics=NUM_OF_TOPICS, id2word=wordMapping, update_every=0)

    print "Saving Model to {0} ..".format(model_name)
    trained_model.save(model_name)

    return trained_model

パラメータwordMappingは単語の番号をインデックスに、単語の文字列を値とした辞書である。
これはオプションで、トピックベクトルを表示するときなどに単語を表示させることが出来て便利 という程度のものなので面倒くさければ必要なし。

学習データであるvectorsは、ここでは2次元のベクトルで、各行が各単語を表していて(これがトピックモデルでいう「文書」に対応する)、各列がその行の単語と各インデックスの単語との共起回数を表す。i 行 j 列目はインデックスi の単語とjの単語の共起回数だ。このデータは文書集合から自分で作るも良し、どこかのソースから取ってくるもよし、とにかく自分で用意しなければいけない。(つまりここではLDAはベクトルの次元縮約として働く)
このベクトルは当然スパースになるので、gensimではスパースコーディングで渡す。つまり、0でない成分のインデックスとその成分の組のリストとして渡す。つまり、[1,0,0,4,0,0,8]は[(0,1), (3,4), (6,8)]と表される。

普通のリストをスパースコーディングに変換する関数は、例えば以下のように書ける。

def convert_to_sparse(dense_vector):
    is_sparse = lambda vector: isinstance(vector[0], tuple)
    if not is_sparse(dense_vector):
        return [(i,v) for i,v in enumerate(dense_vector) if v > 0]
    else:
        return dense_vector

num_topicsに指定するのはベクトルの次元数(トピック数)で、大きければ表現力は上がる一方オーバーフィットしやすく計算量は増すので、100〜300くらいがちょうどよい。

gensimのLdaModelオブジェクト標準のメソッドsaveでモデルが保存できるので、一度学習して保存しておけば次回以降はすぐに読み込んでモデルを利用することができる。便利だ。

 

類似度比較

最も簡単な応用例として、類似度比較を試してみた。今回は得られたベクトルを使って単語 home, house, timeの類似度を測ってみた。類似度はコサイン類似度を用いている。

    \begin{eqnarray*} cos(\bm{u}, \bm{v}) = \frac{\bm{u}\cdot\bm{v}}{|\bm{u}||\bm{v}|} \end{eqnarray*}

以下がLDAの結果(トピック数100)だ。

Similarity between house.n and home.n is 0.432761038721
Similarity between house.n and time.n is 0.248780840955
Similarity between home.n and time.n is 0.21364984806

直観に違わず、homeとhouseの類似度がtimeとhouseの類似度を大きく上回っている。

ちなみに、学習に使った共起表現の生ベクトル(ボキャブラリーサイズ=ベクトルの次元数=2000)で同じく類似度を計った結果が以下である。

Similarity between house.n and home.n is 0.812743856464
Similarity between house.n and time.n is 0.82359219053
Similarity between home.n and time.n is 0.818144793373

ベクトルが長く、スパース過ぎて0がほとんどなため、コサイン相関だと差がほとんどあらわれない。上2つを比較すれば、いかにLDAの次元圧縮が効いているかわかる。

Pocket

Published in人工知能自然言語処理

2 Comments

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です