"BOKU"のITな日常

BOKUが勉強したり、考えたことを頭の整理を兼ねてまとめてます。

PythonでWord2Vec学習済モデルを使う単語の足し算・引き算を簡単にためすクラス

f:id:arakan_no_boku:20190201220606j:plain

目次

事前学習済Word2Vecモデル

今回は、GitHubで公開されている事前学習炭モデルを使います。

Wikipediaの各国語版テキストを元に、Word2Vec(w)とFastText(f)の両方の事前学習済モデルがダウンロードできるようにしていただいているものです。

github.com

ここから、「Japanese(w)」(日本語のWord2Vec)をダウンロードします。

ja.zipという名前のファイルを解凍します。

jaというフォルダを、pythonソースを置くフォルダにコピーしときます。

Gensimのインストール

Word2Vecのロードとトピック分析には「Gensim」を使います。

はいってない場合は

pip install gensim

でインストールしときます。

Word2Vecモデルのロードとトピック分析

後々の再利用を考えてクラスにしておきます。

word2vec.pyのソース
import gensim


class Word2Vec:
    def __init__(self):
        self.model = gensim.models.Word2Vec.load('.\\ja\\ja.bin')

    def get_most_similar(self, plus_list, minus_list):
        error_list = []
        plus = []
        for p in plus_list:
            if p in self.model.wv.vocab:
                plus.append(p)
            else:
                error_list.append(p + 'はボキャブラリに存在しません')
        minus = []
        for m in minus_list:
            if m in self.model.wv.vocab:
                minus.append(m)
            else:
                error_list.append(m + 'はボキャブラリに存在しません')
        try:
            if not minus:
                if not plus:
                    result = [('検査対象はありませんでした。', 0.99999999)]
                else:
                    result = self.model.most_similar(positive=plus)
            else:
                if not plus:
                    result = self.model.most_similar(negative=minus)
                else:
                    result = self.model.most_similar(
                        positive=plus, negative=minus)
        except BaseException:
            result = [('処理中にエラーが発生しました。', 0.99999999)]
        return result, error_list

とりあえず、初期化と類似語を返す「get_most_similar()」だけ実装してます。 

ソースの補足説明

Wikiの学習済Word2Vecモデルは、jaフォルダ下の「ja.bin」をロードして構築です。 

self.model = gensim.models.Word2Vec.load('.\\ja\\ja.bin') 

言葉の計算のため、

  • たし算する言葉のリスト「plus_list」
  • 引き算する言葉のリスト「minus_list」

を引数にとります。

gensimの.「most_similar」でトピック分析をします。

positiveに「足し算したいリスト」、negativeに「引き算リスト」を渡します。

.most_similarは、モデルのボキャブラリにない言葉があると例外を発生させるので、try~exceptで囲むのは必須です。

ただ。

ひとつでもボキャブラリにない言葉があるとエラーってのは、いまいち親切ではないので、以下のようにして、先にボキャブラリに対する存在チェックを行います。

if p in self.model.wv.vocab:

 pのところには、引数のリストにセットされた各単語がはいります。

ボキャブラリに存在する言葉だけで引数のリストを構成するようにしてます。

動作確認テスト用ソース

test.pyって名前で作りました。

上記のクラスの使い方は、これを見ればすぐわかるかと思います。

import word2vec as wv

word2vec = wv.Word2Vec()
p = []
m = []

result,error = word2vec.get(p,m)
cnt = 0
for r in result:
    cnt += 1
    if(cnt == 1):
        print('第1候補:' + r[0])
    
    else:
        if(cnt < 5):
            if(r[1] > 0.30000000000):
                print('第' + str(cnt) + '候補:' + r[0])

print('--------------------------------------------------')
for e in error:
    print(e)
   

上記の「p」に足し算する言葉、「m」に引き算する言葉を入れて実行する感じです。

いくつかの言葉で試してみる

pとmにいくつか言葉を入れてためしてみます。 

p = ['世界']/m = ['知性']

ようするに、「世界 - 知性」です。

世界から知性を引き去ると何なのか?

その答えがこちら。

第1候補:日本
第2候補:めてとなる
第3候補:ヘルシンキ
第4候補:香港
--------------------------------------------------

 あはははは。

第一候補が「日本」なんですね。

p = ['猿','知性']/m =

猿に知性を足してみます。

何も引きません。

結果はこちら。

第1候補:感性
第2候補:人間
第3候補:怪物
第4候補:叡智
-------------------------------------------------- 

うーん。

感性・人間・怪物かあ。

なんか、深いな。

p = ['猿','知能']/m =

今度は「知性」を「知能」に変えてみます。

そうすると。

第1候補:ゴリラ
第2候補:二匹
第3候補:怪物
第4候補:イタチ
--------------------------------------------------

 猿に「知性」がつけば「人間」に近づくけど、「知能」だけなら「ゴリラ」だよって。

なんか、すごいですね。

p = ['人間']/m = ['猿']

今度は「人間 - 猿」。

人間から「猿」の部分・・つまり「獣性」・・を除くとどうなるか?

第1候補:自我
第2候補:知性
第3候補:思考
第4候補:自己
--------------------------------------------------

 自我・・かあ。

なんか哲学みたいだな。

最後にp = ['男性','女性']/m = []

最後に「男性 + 女性」をやってみます。

想像通りの回答になるかな?

結果は。

第1候補:レズビアン
第2候補:ゲイ
第3候補:ニューハーフ
第4候補:未婚
--------------------------------------------------

いや、見事。

おもしろいですねえ。

なんで、単語をベクトル化して機械学習するだけで、こんな風に答えがでるようになるのか・・不思議でしょうがないです。

ではでは。