4、5年前くらいに自然言語処理コミュニティで流行ったword2vecというものがある。
「同じ文章にある単語同士は近しい」という仮定のもと、様々な文章を計算することによって100〜200次元(調整次第)の空間に各単語を「ベクトル」で表せるというものだ。
計算にはニューラルネットワークを用いている。僕には説明できるほど理解度が深まってないので、めちゃ分かりやすい記事を紹介する。
こちらも幅広く説明しててわかりやすい。word2vecの何が衝撃だったかも書いてあるので興味がある方はぜ是非。
www.slideshare.net
Wikipediaからモデルを作ってみる
Wikipediaのデータの準備は以前の記事で紹介してある。
from gensim.models import word2vec import logging logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO) # 普通のipa辞書 sentences = word2vec.Text8Corpus('../data/wiki_wakati.txt') model = word2vec.Word2Vec(sentences, size=200, min_count=20, window=15) model.save("../data/wiki.model") # mecab-ipadic-NEologdの辞書 sentences_neo = word2vec.Text8Corpus('../data/wiki_wakati_neo.txt') model_neo = word2vec.Word2Vec(sentences_neo, size=200, min_count=20, window=15) model_neo.save("../data/wiki_neo.model")
RNNを利用して大量の単語を200(size)次元に圧縮する。window(文脈の最大単語数)はチューニングする上で重要らしく、ここをいじることで適切なモデルを構築が可能とのこと。
コサイン類似度から近しい単語の抽出
全単語をベクトルで表せるということは、その単語周辺にある単語も抽出できる。「エンジニア」に近しい単語を計算してみる。
from gensim.models import word2vec model = word2vec.Word2Vec.load("../data/wiki.model") results = model.wv.most_similar(positive=['エンジニア']) for result in results: print(result)
納得できそうな単語が並んだと思う。
('プログラマー', 0.654212474822998) ('アーキテクト', 0.639656662940979) ('デザイナー', 0.6255037188529968) ('システムエンジニア', 0.6227017641067505) ('エンジニアリング', 0.6170016527175903) ('チーフ', 0.6166958212852478) ('ディレクター', 0.6148343086242676) ('技師', 0.610156774520874) ('コンサルタント', 0.6077147722244263) ('テクニカルディレクター', 0.5718519687652588)
ベクトルによる足し算引き算を行う
もちろん足し算と引き算もできる。実際に「エンジニア」から「アーキテクト」を引いてみるとどうなるかやってみる。イメージとしては、「コーダー」的なイメージだが・・。
まずはipa辞書でやると
from gensim.models import word2vec model = word2vec.Word2Vec.load("../data/wiki.model") results = model.wv.most_similar(positive=['エンジニア'], negative=['アーキテクト']) for result in results: print(result) ('ジミ・ヘンドリックス', 0.4125749170780182) ('ミキサー', 0.39917922019958496) ('ドラム', 0.3988112211227417) ('ミックスダウン', 0.3903549015522003) ('フィーリング', 0.38688427209854126) ('ストリングス', 0.38426920771598816) ('フェンダー・ストラトキャスター', 0.3818718492984772) ('ハモンドオルガン', 0.38104212284088135) ('エントウィッスル', 0.3800022602081299) ('ソニー・ロリンズ', 0.37943196296691895)
音楽関連のワードがでてきた・・・。歌って踊れるエンジニアから、踊れるを抜いた状態なのだろうか。
次にNEologdの辞書で行ってみると
プログラマープログラマー from gensim.models import word2vec <200b> model = word2vec.Word2Vec.load("../data/wiki_neo.model") results = model.wv.most_similar(positive=['エンジニア'], negative=['アーキテクト']) for result in results: print(result) ('ジャコ', 0.38521867990493774) ('苦労', 0.37028828263282776) ('ミキサー', 0.35078269243240356) ('クルー', 0.34380707144737244) ('高所恐怖症', 0.3329920172691345) ('テープレコーダー', 0.3325659930706024) ('運転手', 0.3293205499649048) ('パム', 0.32380378246307373) ('スタッフ', 0.32033008337020874) ('機材', 0.3194393217563629)
音楽関連のジャコ出会って欲しいが、2番目が「苦労」となると「雑魚」の可能性もありえるな・・・。アーキテクトができないエンジニアはダメということか。。
終わりに
僕のチューニング不足であまりよくない結果になってしまったが、word2vecがすごいことは理解できた。
次はもう少し意味のある実践したいなー。