gensimのWord2Vecを使ってみたので、使用方法をまとめました。

今回コーパスは『極性分析できのこたけのこ戦争に決着をつける』の記事で集めたツイートのデータを使用します。小規模なコーパスなので上手くいかない可能性もありますが練習ということであまり気にしません。




Word2Vecとは


Word2Vecは大量のテキストデータを解析し、単語をベクトル化する方法です。

単語をベクトル化することで単語同士の類似度を計算したりすることができます。

今回の場合きのこの山とたけのこの里のツイートをWord2Vecを用いて分析するということできのこの山とたけのこの里はお菓子の名前という同じカテゴリなので二つの単語のベクトルは近いものになるはずです。


実行環境


  • Windows10
  • Python3.6
  • gensim3.4.0
  • MeCab(辞書はmecab-ipadic-Neologdを使用)
MeCabのインストール方法や辞書の変更方法は以下の記事にまとめています。

Python3でMeCabを動かしてみる(Windows10 64bit)

MeCabのNEologd辞書をWindows10で使う方法



gensimのインストール


gensimは以下のコマンドだけでインストールすることができます。
pip install gensim
anacondaを使っていてpipではインストールができない場合は次のコマンドを使ってください
conda install -c anaconda gensim



学習データの準備


コーパスは最初に述べた通りツイートのデータを使うのですがWord2Vecの学習を始める前に学習データを分かち書きにして単語と単語の間をスペースで区切った状態に変更する必要があります。

またWord2Vecでモデルを作成するさいは助詞、助動詞などの非自立語は除外したほうが精度の良いモデルを作成することができるため今回は名詞、形容詞、動詞以外の単語は除外します。

"たけのこの里が好きだ。" という文があった場合は "たけのこの里 好き" といった状態に変更します。

学習データの準備は以下のコードで実行しました。
# -*- coding: utf-8 -*-
# 学習データをgensimで使える型に変換

import MeCab

# テキストを名詞、形容詞、動詞を残した分かち書きに変換
def wakachi(text, file):
  tagger = MeCab.Tagger("-Ochasen -d C:\mecab-ipadic-neologd")
  node = tagger.parseToNode(text)
  while node:
    # 名詞、形容詞、動詞だけリストに追加
    if (node.feature.split(',')[0] == '名詞' or node.feature.split(',')[0] == '形容詞' or node.feature.split(',')[0] == '動詞') and node.feature.split(',')[6] != '*':
      try:
        file.write('{} '.format(node.feature.split(',')[6]))
      except:
        pass
    node = node.next
  
# tweetを読み込み
def loadtweet(filename):
  tweet = []
  with open(filename) as f:
    for i in f:
      try:
        tweet.append(i.rstrip())
      except:
        pass
    return tweet
  
def main():
  tweet = loadtweet("tweet/kinoko_tweet.txt")
  wakachi_file = "kinoko_wakachi.txt" # 書き込み先のファイル名
  
  with open(wakachi_file, 'w') as f:
    for i in tweet:
      wakachi(i, f)
      f.write('\n')

if __name__ == '__main__':
  main()
今回私はtweetを対象に行っていますがどんなコーパスを使用してもこのコードで対応できるはずです。

コード中に例外処理をいれていますがこれは文字コード関係でエラーを起こしてしまい今回はあまり厳密にデータをしなくてもいいかということで簡単に片づけています。



Word2Vecのモデル作成


Word2Vecのモデルの作成は自分で一からコードをかこうとすると結構大変ですが、gensimを使えば10行もかかりませんでした。

モデルの作成は以下のコードで行いました。
# -*- coding: utf-8 -*-
# Word2Vecのモデルを作成
from gensim.models import word2vec

data = word2vec.LineSentence("kinoko_wakachi.txt")
# モデルを作成
model = word2vec.Word2Vec(data, size=200, window=10, hs=1, min_count=2, sg=1)
# モデルを保存
model.save('kinoko.model')
モデルを作成するWord2Vecメソッドのオプションでは、生成するベクトルの次元数や、単語の最大距離を設定することができます。

sizeは生成するベクトルの次元数です。今回は200次元にしています。
windowは単語の最大距離です。今回は10にしています。
hsは学習にsoftmax関数を使うかどうかです。(0の場合は使わない、0以外の値では使う)
min_countはこの値より出現回数の少ない単語を無視します。
sgは学習アルゴリズムの設定です(0の場合はCBOW、1の場合はskip-gram)。今回は何かの論文でskip-gramの方が良い結果になりやすいと見た記憶があるのでskip-gramを使いました。


生成したWord2Vecのモデルを使ってみる


modelの読み込み
model = word2vec.Word2vec.load('kinoko.model')
単語のベクトルの確認
# きのこの山のベクトルを確認
word_vector = model.wv["きのこの山"]
似た単語を列挙
# きのこの山と類似している単語の確認
similar_words = model.wv.most_similar(positive=["きのこの山"], topn=9)
print(similar_words)
[('満足', 0.6623457670211792), ('NI', 0.6556951999664307), ('きのこ派', 0.6542500257492065), ('最高かよ', 0.6375962495803833), ('アイス', 0.6262195110321045), ('4m', 0.6219021081924438), ('ファン', 0.6202322244644165), ('永遠', 0.6201416850090027), ('ムース', 0.619083821773529)]
きのこの山に類似している単語にたけのこの里がないのは意外でした。アイスやムースなどの他の食べ物があるため学習データを増やせばたけのこの里も類似している単語として出現するのかもしれません。

語句の線形計算
# 線形計算(きのこの山-きのこ=???)
print(model.most_similar(positive=['きのこの山'], negative=['きのこ'])[0])
('木村', 0.4005602300167084)
"きのこの山-きのこ" をしてみると "木村" という謎の結果になりました。(なにがでたら正解かは分からないが...)

positiveに加算する単語、negativeに減算する単語を入れます。"父-男+女" のように複数の単語を用いた計算を行うことができます。

色々な語句の線形計算を行ってみると楽しそうな気がします。


最後に


この記事ではgensimを使ってWord2Vecのモデルを作成しました。

今回は小規模なコーパスを使ってモデルを作成しましたが、次することがあればもう少し大きなコーパスを使ってモデルを作成して文の類似度を測るなど応用した方法を実行してみようと思います。