Word2VecをPythonでやってみる
ちょっと前から、自然言語処理分野を騒がせている「Word2Vec」という手法があります。これは、文章(単語の羅列)から単語の前後関係やらを用いて、単語のベクトルを学習しようと言うものです(たぶん)。
このベクトルというのが面白いもので、ベクトル間の距離が小さ(内積が大き)ければ、その二つの言葉は近い存在(ex. 犬と猫 や JPGとPNG など)ということになります。さらに、ベクトルであるがゆえに、それらの足し算・引き算ができます。このことが意味するのは・・・。
突然ですが、あなたは以下の式の「?」には何が当てはまると思いますか?
王様 – 男性 + 女性 = ?
初見では、いまいちパッとこないかもしれませんが、この式が一番有名な例となっております。で、この式は「女王」がいい感じに当てはまるはずです。おまけに、もう一つ例を挙げてみます。
本 – 読む + 歌 = ?
上記の式とは雰囲気が変わりましたが、この式が意味しているところは「本といえば読むだけど、歌といえば?」です。つまりこの式の答えは、歌う(or聞く)になります。
このような「感覚」的な動作は、コンピュータには難しかったのですが、この手法を使用することで(ツールが公開されているので)、簡単に私にもできました。
OS : Ubuntu14.04 LTE版
Python: 2.7.6(Word2Vec処理)
Python: 3.4.0(日本語の分かち書き)
MeCab : ver0.996
gensim: 0.11.1
1. コーパスの準備
上記で示した答えが返ってくるには、計算をさせる前にコンピュータ君に学習させておく必要があります。というわけで、学習用のテキストを用意しなくてはいけません。ここでいうところのテキストは、単語の羅列で、それぞれの語は半角スペースで区切られている形式、つまりは、分かち書きの形式になっているものです。その点、英語は元々分かち書きになっているので、そのままで大丈夫ですが、日本語は残念ながら自分で分かち書く必要があります。
_____日本語で頑張りたい人へ_____
今回は、自然言語処理界隈ではおなじみのMeCabを使って分かち書いていきます。具体的なインストールの方法や使い方はこの前の記事で書いたので、そこを参照してください。
学習にはかなり大量のデータ量(100万語以上)が必要になるので、特別テキストファイルのない方は、青空文庫あたりから持ってきてください。ある程度集まったら、それをMeCabによって分かち書きにしてください。今回は、Pythonのプログラムで仕上げました。
追記 2016/12/2
Juman++を推しましたが、やはりお手軽さではMeCabに軍配が上がるので、MeCabを使った分かち書きプログラムを掲載しましたので、よかったらそちらの記事を参考にしてみてください。簡単なインストールの作業記録も一緒にどうぞ。
追記 2016/11/15
この記事を書いた際は分かち書きを行うときにMeCabを使用していまいたが、現在はJuman++というツールも使用しています。簡単なインストール方法はこちらで紹介しています。
_____英語でとりあえず試したい人へ_____
とりあえず、Word2Vecの動作を見てみたいという人には、公式で用意されているテスト用のデータを使用してください。以下のコマンドで入手することができます。
1 2 |
$ wget http://mattmahoney.net/dc/text8.zip -O text8.gz $ gzip -d text8.gz -f |
ただし、Pythonでこの量(1000万語くらい)を学習させるとなると、時間がかかりすぎるので、C言語で実装されているものか、語数を減らしてからお試しください。
2. Word2Vecのインストール
こんかい使用するWord2Vecの実装は、Pythonのライブラリであるgensimの中にあります。なので、今回はこれを使います。以下のコマンドでインストールしてください。
1 |
$ sudo easy_install gensim |
お手軽万歳。
3. 学習。
では、上記で用意したコーパスを使ってWord2Vecの学習をしていきましょう。具体的には、Word2Vec内のニューラルネットワークを学習させているみたいです。
以下のプログラムを実行してみてください。結果として、’sample.model’というモデルを出力します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# -*- coding: utf-8 -*- from gensim.models import word2vec import logging # 進捗表示用 logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO) # Word2Vecの学習に使用する分かち書き済みのテキストファイルの準備 sentences = word2vec.Text8Corpus('out.txt') # Word2Vecのインスタンス作成 # sentences : 対象となる分かち書きされているテキスト # size : 出力するベクトルの次元数 # min_count : この数値よりも登場回数が少ない単語は無視する # window : 一つの単語に対してこの数値分だけ前後をチェックする model = word2vec.Word2Vec(sentences, size=200, min_count=20, window=15) # 学習結果を出力する model.save("sample.model") if __name__ == '__main__': print "Finish!!!" |
4. 学習の結果を確認してみる
さて、では結果を確認してみましょう。以下のようなプログラムで単語間の距離が分かります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#!/usr/bin/env python # -*- coding: utf-8 -*- from gensim.models import word2vec import logging import sys # 学習済みモデルのロード model = word2vec.Word2Vec.load("sample.model") # 入力された単語から近い単語をn個表示する def s(posi, nega=[], n=10): cnt = 1 # 表示した単語の個数カウント用 # 学習済みモデルからcos距離が最も近い単語n個(topn個)を表示する result = model.most_similar(positive = posi, negative = nega, topn = n) for r in result: print cnt,' ', r[0],' ', r[1] cnt += 1 if __name__ == '__main__': word = sys.argv[1] word = unicode(word, 'utf-8') s([word]) |
ここで重要なのは、most_similarという関数のところです。足し算・引き算はそれぞれpositiveとnegativeの引数に対応しています。なので、上記の式の場合は以下のようになります。
1 |
model.most_similar(positive = ["本","歌"], negative = ["読む"], topn = n) |
これにて、おわりです。お疲れ様でした。
コーディングで分からないことがあれば
プログラミングや環境構築で分からないことがあったら『teratail』というエンジニア特化型のQ&Aサービスがオススメです。自分もどうしても分からないことがあったら、時々質問しにいきますが、かなりニッチな質問にも意外と早く回答がつくのでとても頼もしいです。という宣伝でした。
「word2vec」(Googleの公式)
「青空文庫のデータでWord2Vec」