"BOKU"のITな日常

還暦越えの文系システムエンジニアの”BOKU”は新しいことが大好きです。

Word2Vec学習済モデルとgensimで「世界」-「知性」=を計算したら「日本」になった(笑)

今回と次回で事前学習済Word2Vecモデルを使って、簡単なデモを作ってみます。

f:id:arakan_no_boku:20190201220606j:plain

まず、学習済モデルをロードして、入力をうけとって結果を返すpythonプログラムを用意して、次回でdjangoに組み込んでみます。

 

事前学習済Word2Vecモデル

 

GitHubで公開されています。

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

有難いですねえ。

github.com

今回はここから、「Japanese(w)」(ようするに、日本語のWord2Vec)をダウンロードします。

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

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

 

Gensimのインストール

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

はいってない場合は

pip install gensim

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

 

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

 

次回、djangoで画面つくって、簡単なデモに仕上げたいので、クラスにします。

 

word2vec.pyのソース
import gensim

class Word2Vec:
    def __init__(self):
        self.model = gensim.models.Word2Vec.load('.\\ja\\ja.bin')
 
    def get(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:
            result = [('処理中にエラーが発生しました。',0.99999999)]
        return result,error_list
 

とりあえず、初期化とトピック分析の結果を返す「get()」だけ実装してます。 

 

ソースの補足説明

 

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候補:未婚
--------------------------------------------------

いや、見事。

おもしろいですねえ。

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

ではでは。