LoginSignup
6
4

More than 3 years have passed since last update.

言語処理100本ノック-90(Gensim使用):word2vecによる学習

Posted at

言語処理100本ノック 2015の90本目「word2vecによる学習」の記録です。
今まで第9章でやってきた内容をパッケージ使って簡単にやってしまおう、という設問です。メモリ不足などを気にしながら必死にやってきた内容が3行程度のコードでできてしまうのは、拍子抜けな反面素晴らしさを痛感します。
今回は設問で指定されているGoogle社のword2vecを使わずにオープンソースのGeinsimを使っています。パッケージの更新頻度も多く、よく使われていると聞いたことがあるからです(にわか知識で、しっかりと調べていません)。

参考リンク

リンク 備考
090.word2vecによる学習.ipynb 回答プログラムのGitHubリンク
素人の言語処理100本ノック:90 言語処理100本ノックで常にお世話になっています

環境

種類 バージョン 内容
OS Ubuntu18.04.01 LTS 仮想で動かしています
pyenv 1.2.15 複数Python環境を使うことがあるのでpyenv使っています
Python 3.6.9 pyenv上でpython3.6.9を使っています
3.7や3.8系を使っていないことに深い理由はありません
パッケージはvenvを使って管理しています

上記環境で、以下のPython追加パッケージを使っています。通常のpipでインストールするだけです。

種類 バージョン
gensim 3.8.1
numpy 1.17.4

課題

第10章: ベクトル空間法 (II)

第10章では,前章に引き続き単語ベクトルの学習に取り組む.

90. word2vecによる学習

81で作成したコーパスに対してword2vecを適用し,単語ベクトルを学習せよ.さらに,学習した単語ベクトルの形式を変換し,86-89のプログラムを動かせ.

回答

回答プログラム 090.word2vecによる学習.ipynb

from pprint import pprint

from gensim.models import word2vec

corpus = word2vec.Text8Corpus('./../09.ベクトル空間法 (I)/081.corpus.txt')

model = word2vec.Word2Vec(corpus, size=300)
model.save('090.word2vec.model')

# 86. 単語ベクトルの表示
pprint(model.wv['United_States'])

# 87. 単語の類似度
print(np.dot(model.wv['United_States'], model.wv['U.S']) / (np.linalg.norm(model.wv['United_States']) * np.linalg.norm(model.wv['U.S'])))

# 88. 類似度の高い単語10件
pprint(model.wv.most_similar('England'))

# 89. 加法構成性によるアナロジー
# vec("Spain") - vec("Madrid") + vec("Athens")
pprint(model.wv.most_similar(positive=['Spain', 'Athens'], negative=['Madrid']))

回答解説

単語ベクトル生成

まずはファイル読込です。Text8Corpus関数を使っている例が多いなと思い、そもそもText8Corpusとは何と思って調べました。
記事「日本語版text8コーパスを作って分散表現を学習する」によるとtext8とは以下の処理をしたWikipediaのデータらしい。

  • テキストと画像キャプションは保持
  • テーブルや外国語バージョンへのリンクを除去
  • 引用、脚注、マークアップを除去
  • ハイパーテキストはアンカーテキストだけ保持。それ以外は除去
  • 数字はつづりを変換。たとえば、"20"は"two zero"に変換
  • 大文字を小文字に変換
  • a-zの範囲に入らない文字はスペースに変換

大文字はあった気もするが、だいたい条件に合致している気がしたのでText8Corpusを使いました。

corpus = word2vec.Text8Corpus('./../09.ベクトル空間法 (I)/081.corpus.txt')

あとはWord2Vec関数を使うだけで300次元の単語ベクトル完成です。4分弱で生成できました。すごい・・・
オプションは使わなかったですが、gemsimのword2vecのオプション一覧がわかりやすかったです。

model = word2vec.Word2Vec(corpus, size=300)

そして、後続のノックのためにファイル保存しておきます。

model.save('090.word2vec.model')

そうすると以下の3ファイルができるようです。1つでないのが気持ち悪いです。

ファイル サイズ
090.word2vec.model 5MB
090.word2vec.model.trainables.syn1neg.npy 103MB
090.word2vec.model.wv.vectors.npy 103MB

86. 単語ベクトルの表示

85で得た単語の意味ベクトルを読み込み,"United States"のベクトルを表示せよ.ただし,"United States"は内部的には"United_States"と表現されていることに注意せよ.

model.wvにベクトルが入っているので指定してあげるだけです。

pprint(model.wv['United_States'])
array([ 2.3478289 , -0.61461514,  0.0478639 ,  0.6709404 ,  1.1090833 ,
       -1.0814637 , -0.78162867, -1.2584596 , -0.04286158,  1.2928476 ,
結果略

87. 単語の類似度

85で得た単語の意味ベクトルを読み込み,"United States"と"U.S."のコサイン類似度を計算せよ.ただし,"U.S."は内部的に"U.S"と表現されていることに注意せよ.

modelを使って第9章と同じベクトル同士のコサイン類似度計算をします。
第9章では0.837516976284694だったので、より類似度が高い数値が出ています。

print(np.dot(model.wv['United_States'], model.wv['U.S']) / (np.linalg.norm(model.wv['United_States']) * np.linalg.norm(model.wv['U.S'])))
0.8601596

88. 類似度の高い単語10件

85で得た単語の意味ベクトルを読み込み,"England"とコサイン類似度が高い10語と,その類似度を出力せよ.

modst_similar関数を使うだけで出力できます。

pprint(model.wv.most_similar('England'))
[('Scotland', 0.7884809970855713),
 ('Wales', 0.7721374034881592),
 ('Ireland', 0.6838206052780151),
 ('Britain', 0.6335258483886719),
 ('Hampshire', 0.6147407293319702),
 ('London', 0.6021863222122192),
 ('Cork', 0.5809425115585327),
 ('Manchester', 0.5767091512680054),
 ('Liverpool', 0.5765234231948853),
 ('Orleans', 0.5624016523361206)]

ちなみに第9章での結果は以下の通りでしたが、今回はイギリスに関連する単語がより上位に出てきていて、より正しいデータが出力されていることがわかります。

Scotland    0.6364961613062289
Italy   0.6033905306935802
Wales   0.5961887337227456
Australia   0.5953277272306978
Spain   0.5752511915429617
Japan   0.5611603300967408
France  0.5547284075334182
Germany 0.5539239745925412
United_Kingdom  0.5225684232409136
Cheshire    0.5125286144779688

89. 加法構成性によるアナロジー

85で得た単語の意味ベクトルを読み込み,vec("Spain") - vec("Madrid") + vec("Athens")を計算し,そのベクトルと類似度の高い10語とその類似度を出力せよ.

modst_similar関数にpositivenegativeを渡すと計算して、類似度の高い10語を出力してくれます。

pprint(model.wv.most_similar(positive=['Spain', 'Athens'], negative=['Madrid']))
[('Denmark', 0.7606724500656128),
 ('Italy', 0.7585107088088989),
 ('Austria', 0.7528095841407776),
 ('Greece', 0.7401891350746155),
 ('Egypt', 0.7314825057983398),
 ('Russia', 0.7225484848022461),
 ('Great_Britain', 0.7184625864028931),
 ('Norway', 0.7148114442825317),
 ('Rome', 0.7076312303543091),
 ('kingdom', 0.6994863748550415)]

ちなみに第9章での結果は以下の通りでしたが、今回はギリシャも4位に出てきていてより正しいデータが出力されていることがわかります。

Spain   0.8178213952646727
Sweden  0.8071582503798717
Austria 0.7795030693787409
Italy   0.7466099164394225
Germany 0.7429125848677439
Belgium 0.729240312232219
Netherlands 0.7193045612969573
Télévisions   0.7067876635156688
Denmark 0.7062857691945504
France  0.7014078181006329
6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4