ネット上にあちこち記事がある。山内のメモは こんな感じ
似たような話として Python - Perl + Java = ? はてなブログのデータとパソコン工房のPCを使って「word2vec」で遊んでみた コーパスが圧倒的に強い。
ウィキペディアの記事をコーパスとするために、形態素解析(MeCabなど)を 使って名詞だけ抜き出すことを試したが、結果があまり面白くないので、 他の人がやっているように →参照 分ち書きにするだけで済ませる。
gensimのword2vecモジュールの使い方は、チュートリアルとしては radimrehurekのページ に書いてあるが、使い方としては学習部分と、similarityとかだけである。 もう一歩突っ込んだ記述は APIのマニュアルページ にある。
学習のためのプログラムは、チュートリアルにある通りのものを使う。
#!/usr/bin/env python # -*- coding: utf-8 -*- import gensim, logging import sys import string, codecs sys.stdout = codecs.getwriter('utf_8')(sys.stdout) logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO) sentences = gensim.models.word2vec.Text8Corpus("wp2txt/wp2wakati.txt") # train word2vec on the two sentences model = gensim.models.word2vec.Word2Vec(sentences, workers=28, min_count=5) print "model gen complete" model.save("jpw-wakati-model")
チュートリアルに出てくる、テスト部分のプログラムは、
#!/usr/bin/env python # -*- coding: utf-8 -*- import gensim, logging import sys import string, codecs sys.stdout = codecs.getwriter('utf_8')(sys.stdout) logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO) model = gensim.models.word2vec.Word2Vec.load("jpw-wakati-model") print "model load complete" out = model.most_similar(positive=[u'パリ', u'フランス'], negative=[u'ベルリン'], topn=5) out = model.most_similar(positive=[u'剣道'], negative=[u'剣'], topn=5) out = model.most_similar(positive=[u'日本', u'ロンドン'], negative=[u'東京'], topn=5) for x in out: for y in x: print y, '\t', print print model[u'剣道']
のようなものにできる。
チュートリアル等ではsimilarityを中心にしているが、ベクトル空間を直接に見れば、もう少しいろいろがこと(たとえば距離を計算してクラスタ化してみるとか)が試せるのではないか。
2つの要素が欲しい。登録されている語(vocaburary)を取り出すことと、それに対応するベクトルを取り出すことである。もちろん、全データがタイトル付きの1つの配列(ExcelやRの表のように)になっていれば、それを使えばいいのだが、そのような記述は見当たらないので、自分で取り出してみる。(余分な手間をかけているかもしれない)
まず、登録されている語のリストを取り出すには、
voc = model.vocab.keys()
のようにすればできる。
また、特定の語 x に対するベクトルを取り出すには、
wvec = model[x]
とすればよい。但し、その語が登録されていないと、KeyErrorを返すので、例外対策をしておいたほうがいい。
wv = []; vocnew = [] for x in voc: try: wv.append(model[x]) except KeyError: print x, u'を無視します' vocnew.append(x)
では、これらを使って語のクラスタ化を試してみる。まずは、特定の幾つかの語に対して、ベクトル間のユークリッド距離(必要に応じて距離関数は変えてもいい)に基づいて、クラスタ化してみる。
クラスタ化は、階層的クラスタ化と階層なしのクラスタ化があるが、まず興味があるのは、語の間の関係(たとえばis-a関係、包含関係)がベクトルクラスタの階層として現れるのかどうか、についてである。となると、階層的クラスタ化をして見ることになる。 (階層なしの場合、クラスタ数をあらかじめ指定しなければならず、これはちょっと頭が痛い。AICとかを用いる話があるが、それはさておくことにする。)
#!/usr/bin/env python # -*- coding: utf-8 -*- ############### # jpwiki --> word2vec --> vectors --> hierarchical clustering ############### import gensim, logging import sys import string, codecs sys.stdout = codecs.getwriter('utf_8')(sys.stdout) ######################### # python/scipyを使って階層的クラスタリング+系統樹を描く # 参照: http://openbook4.me/users/1/sections/783 # マニュアルは: http://docs.scipy.org/doc/scipy/reference/generated/scipy.cluster.hierarchy.linkage.html#scipy.cluster.hierarchy.linkage ######################### import scipy.spatial.distance import scipy.cluster.hierarchy import matplotlib from matplotlib.pyplot import show font = {'family': 'VL Gothic', 'size': '9' } matplotlib.rc('font', **font) logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO) model = gensim.models.word2vec.Word2Vec.load("jpw-wakati-model") print "model load complete" # Use a handmade vocaburary list (to get clustered) # In next step, use the entire registered vocaburary by #voc = model.vocab.keys() wv = [] vocnew = [] #voc = [u'首都', u'東京', u'パリ', u'ロンドン', u'モスクワ', u'都市', u'大阪', # u'京都', u'ニューヨーク', u'ロサンゼルス', u'リバプール'] #voc = [u'動物', u'イヌ', u'ネコ', u'ブタ', u'サル', # u'植物', u'サクラ', u'バラ', u'イネ'] voc = [u'ビール', u'日本酒', u'焼酎', u'蕎麦', u'スパゲッティ', u'ハンバーグ', u'カレー', u'バラ', u'桜'] for x in voc: try: wv.append(model[x]) except KeyError: print x, u'を無視します' vocnew.append(x) # linkage配列を作る #l = scipy.cluster.hierarchy.linkage(d) #l = scipy.cluster.hierarchy.linkage(wv, method='ward') l = scipy.cluster.hierarchy.linkage(wv, method='average') print l # dentrogramに表現する scipy.cluster.hierarchy.dendrogram(l, labels=vocnew) show()
matplotlibによりたとえばXWindowに樹形図が表示される。
結果は、
左の図では、日本の都市(東京、大阪、京都)がうまくクラスタに入っていないが、 海外の都市は、都市の下に、首都のクラスタとそれ以外があり、首都にはロンドン、パリ、モスクワが入り、それ以外にはリバプール、ニューヨーク、ロサンゼルスが入っている。つまり
{都市, {首都, {ロンドン, パリ, モスクワ}}, {リバプール, ニューヨーク, ロサンゼルス}}
という感じになっているように見える。偶然かもしれないが、かなりうまくできていると思う。
それに反して右の図は、かなりうまくいっていない。ward法で分類している。 (ビール、日本酒、焼酎)と、(スパゲッティ、カレー、ハンバーグ、蕎麦)と(桜、バラ)がグループになることを期待したのだが、(蕎麦、焼酎)が近くにあったりして、何が起こっているのかよくわからない。「蕎麦焼酎」にでもひっかかったのだろうか?
更にもう少し考えてみる >>> gensim-word2vecでベクトル空間を試す(2)