kuro_reraのブログ

新米エンジニアのブログ。いろいろと模索中。

Word2VecでWikipediaに現れる単語の意味を学習する

自然言語処理においては、単語に「意味」をもたせることで文章を「解釈」する。
ここでいう「意味」はベクトルで表すことを示す場合が多い。
手法はTF-IDFやWord2Vecなどさまざまだが、いずれも大量の文章群から文章/単語の特徴を数値化するものだ。

Wikipediaから単語の意味を学習する

ここでは、「大量の文章群」としてWikipediaの記事を選択する。
また、形態素解析にはMeCab(辞書はmecab-ipadic-NEologd)を利用する。
(MeCabの環境設定についてはこちらも参照ください)
Wikipediaからの文章抽出にあたってこちらの記事を参考にさせていただいた。 Wikipediaの文章は、ここから取得できる。
全記事だとあまりに膨大になってしまうので、ここでは分割されたもの(jawiki-latest-pages-articles.xml-*****.bz2)をダウンロードした。

ダウンロードファイルにはXML形式の記事が圧縮されている。
これをWikiextractorというスクリプトを用いて文章だけを取り出す。

$ git clone https://github.com/attardi/wikiextractor.git
$ python wikiextractor/WikiExtractor.py -b 100M jawiki-latest-pages-articles*.xml-******.bz2

-bは文書ファイル1つあたりのサイズを指定するオプションである。
デフォルトは1MBだが、これだと数百ファイルできてしまうので、ある程度の量を指定するといいだろう。
出力ファイルを指定したい場合は、-oオプションを使えばよい。
文章だけ取り出すのには1時間弱必要とした。

作成されたファイルをcatコマンドで連結する。

$ cat wiki_* > corpus

こうしてコーパスが作成された。

単語ベクトルを作成する

コーパスから単語ベクトルを作成するにあたって、まず文章を単語ごとに分かち書きする。
分かち書きの方法もさまざま(助詞は除くなど)だが、今回は単純に分かち書きしてみる。

$ mecab corpus -O wakati -o corpus_wakati

-oは出力ファイル名を指定するオプションである。
これで、Wikipediaから単語の意味を学習することができた。

Word2Vecで遊んでみる

単語を学習できたので、これを使って遊んでみる。
それぞれの単語はベクトルで表されているわけだが、似ている単語のベクトルは似ているといえよう。
most_similar関数を使うと、入力に対し近い単語を出力してくれる。

from gensim.models import word2vec
model = word2vec.Word2Vec.load('model_wiki')
print(model.most_similar('野球'))
[('サッカー', 0.8565059304237366), 
('ボクシング', 0.7676202654838562), 
('ラグビー', 0.7625299096107483), 
('プロレス', 0.7522695660591125), 
('柔道', 0.7483185529708862), 
('プロ野球', 0.7468701601028442), 
('バスケットボール', 0.7369800806045532), 
('レスリング', 0.7255582809448242), 
('スポーツ', 0.7190646529197693), 
('練習', 0.7177714705467224)]

これらの単語が、「野球」に近いとされた単語である。
単語の右の数字はベクトル間のコサインの値を示す。
すなわち、まったく同じベクトルの場合1になり、1に近いほど単語の意味が近いといえる。

most_similar関数は、単語の足し算・引き算を行うこともできる。

print(model.most_similar(positive=['東京', 'フランス'], negative=['日本']))
[('パリ', 0.7332836985588074), 
('ベルリン', 0.7104079723358154), 
('ハンブルク', 0.6936348676681519), 
('ロンドン', 0.6928915977478027), 
('ミラノ', 0.691125214099884), 
('マルセイユ', 0.6871293783187866), 
('ケルン', 0.6853926777839661), 
('ウィーン', 0.6830347776412964), 
('ミュンヘン', 0.6771801114082336), 
('フランクフルト', 0.6715824007987976)]

「東京」-「日本」は首都、大都市のような意味をもつベクトルになるのだろう。
そのベクトルに「フランス」を足すと、予想通り「パリ」が結果として出てきた。

この単語ベクトルを使って、次回は何か面白いことができないかと思っている。