自然言語処理の最新手法"word2vec"で艦これ加賀さんから乳を引いてみる

概要

この記事は自然言語処理という分野の最新手法word2vec
を利用して誰でも遊べるようにするための手順を説明するものです。
word2vecを利用すると意味の計算が実現できます。
例えば"king"から"man"を引いて"woman"を足すと"queen"が出てきたり、
"東京"から"日本"を引いて"フランス"を足すと"パリ"が出てくるという面白い手法です。

自然言語処理とは人間が日常的に用いる自然言語をコンピュータに処理させ、
翻訳や要約、文字入力支援や質問応答システムを作るなどに活用されている分野です。
自然言語処理と言うと耳慣れない言葉かもしれませんが、
実は検索や推薦などで私たちが日常的に利用しているなじみ深い技術でもあります。

自然言語処理の適用範囲や要素技術は幅広いのですが、
その中でもword2vecの特色は、
冒頭でも挙げたように「意味の計算」が出来ることです。
これは今までの技術では実現し得なかったことで、
今後研究が進むにつれどんどん応用が広がっていくことでしょう。
word2vecは2013年ごろ主にMikolov達が発表したもので、
自然言語処理研究者の中でも伸びしろの大きさから
今最も注目されている新技術だと思われます(筆者主観)。
本記事ではword2vecを利用することを主眼としており、
理論的な説明は下記を参照してください。

Statistical Semantics入門の発表をしました


さて、それでは今からword2vecで遊んでみる流れを紹介します。
遊ぶ前に、何を目的としてどのようなデータを利用するかなど
問題設定をして作業の流れを把握しましょう。

■目的・ゴール

艦隊これくしょんの加賀さんから乳を引いてみると
どの艦娘が出てくるか?を調べる。

■理由、応用先

好みの萌えキャラに対して好みの属性を足したり引いたりすることによって
更に萌えるキャラを推薦することが可能になるため。
従来の推薦技術では同じようなジャンルのものばかりを薦めがちであったり、
どのような推薦をして欲しいかをユーザが自由に決定できないという欠点があります。
そこでword2vecを用いることの利点として、従来の推薦技術では成し得ない
「推薦の方向」を操作可能なことが特徴であることが挙げられます。
これによってより良い萌えキャラでブヒれるようになり、
各提督が艦娘の新たな魅力に気づくことによって鎮守府に愛と平和がもたらされる。
なお、数いる艦娘の中から特に加賀さんを選んだ理由は、
艦これの乳と言えば加賀さんであるという
全宇宙の総意に基づいた必然によるものである。
反論は一切認めない、全面的に拒否する。

■作業環境

windows 7*1

■インストールするもの

python2.X(3系だと下記ライブラリが動かないかも…)
mecab(辞書はshift-jis,つまりデフォルト設定で)
gensim(入れる前にscipyなども入れろと言われるかもしれません)

■作業の流れ
  1. テキストデータを2ちゃんねるから取得する
  2. 取得したテキストをword2vecで処理できるよう加工する
  3. word2vecでデータを利用してモデルを作成する
  4. word2vecのモデルを利用して加賀さんから乳を引く

1. テキストデータを2ちゃんねるから取得する

word2vecはデータから学習して意味の計算が可能なモデルを作り出します。
そのためデータを用意する必要があります。
良いデータが無いと良い学習が出来ず、意味の計算結果も直感に沿わないものとなってしまいます。
良いデータとは、出来る限り大量かつゴミを取り除いたものです。
2ちゃんねるのデータのため、大量のタグやAAなどが入っています。
それを本来なら様々な手法とかなりの手作業でクリーニングしていくのですが、
本記事は初心者向けのため最低限の処理を施したものを用意しておいたので、
それを利用して下さい。
DLしてkankore.pyと名前を付けて保存します。
使い方は
python kankore.py url 板フォルダ キーワード(スレタイに指定したキーワード含まれてるスレを取得)
って感じです。
具体的には以下のようにします。

python kankore.py http://uni.2ch.net/ gameswf/ 艦これ > kankore.txt

これで2ちゃんねるのデータを取得してkankore.txtというファイルに保存できます。

2. 取得したテキストをword2vecで処理できるよう加工する

次に、取得したデータを分かち書きします。
英語は各単語の切れ目にスペースを入れますが、
日本語は単語の切れ目を明示的に与えない表記をします。
そのため、どこからどこまでが単語なのかを明示的に与える必要があります。
各単語を空白などで切り分けた表記を分かち書きと言います。
例として、「李も桃も桃のうち」を平仮名にした文を分かち書きすると
すもももももももものうち→すもも も もも も もも の うち
という感じになります。
これも本来ならこの分かち書きするのは結構難しくて色々煩雑な作業があるのですが、
今回は私の方で用意した艦これ辞書を使います。

分かち書きにはmecabを利用します。
これは自然言語処理界隈でデファクトスタンダードなツールです。
インストール作業は簡単なのでこちらなどを見て下さい。
http://handsrecs2nd.seesaa.net/article/140090025.html
mecabをインストール出来たら、用意しておいた艦これ辞書を使います。
これをダウンロードして、mecabフォルダの下にあるdicフォルダに置きます。
mecabフォルダの下にetcフォルダがあるのでそこのmecabrcファイルを開いて
; userdic = /home/foo/bar/user.dic
と書かれた行を
userdic = "C:\(mecabインストールしたフォルダ)\dic\kankore.dic"
と書き換えます。
これで辞書の準備はOKです。

「あきつ丸改二で大発動艇もっと欲しい」という一文をmecabに食わせる場合、
辞書追加前は

>あ フィラー,*,*,*,*,*,あ,ア,ア
>きつ 形容詞,自立,*,*,形容詞・アウオ段,ガル接続,きつい,キツ,キツ
>丸 名詞,固有名詞,人名,姓,*,*,丸,マル,マル
>改 名詞,一般,*,*,*,*,改,アラタメ,アラタメ
>二 名詞,数,*,*,*,*,二,ニ,ニ
>で 助詞,格助詞,一般,*,*,*,で,デ,デ
>大 接頭詞,名詞接続,*,*,*,*,大,ダイ,ダイ
>発動 名詞,サ変接続,*,*,*,*,発動,ハツドウ,ハツドー
>艇 名詞,接尾,一般,*,*,*,艇,テイ,テイ
>もっと 副詞,一般,*,*,*,*,もっと,モット,モット
>欲しい 形容詞,自立,*,*,形容詞・イ段,基本形,欲しい,ホシイ,ホシイ

となりますが、この辞書を追加すると

>あきつ丸 名詞,一般,*,*,*,*,あきつ丸,アキツマル,アキツマル
>改二 名詞,一般,*,*,*,*,改二,,
>で 助詞,格助詞,一般,*,*,*,で,デ,デ
>大発動艇 名詞,一般,*,*,*,*,大発動艇,,
>もっと 副詞,一般,*,*,*,*,もっと,モット,モット
>欲しい 形容詞,自立,*,*,形容詞・イ段,基本形,欲しい,ホシイ,ホシイ

という感じになります。

mecabの準備が整ったらコマンドプロンプトで
mecab -Owakati kankore.txt > wakati_kankore.txt
とやると分かち書きされたファイルが生成されます。
これでようやくword2vecに流し込めます、お疲れ様でした、
真の地獄はこれからだ。

3. word2vecでデータを利用してモデルを作成する

これからgensimを利用してword2vecを実践してみます。
word2vecはgoogle版の実装があってこれ使った方が1.5倍くらい速いのですが、
*2
とりあえず動かす分にはpythonから扱える方が簡単かと思いますので
ここではgensimというライブラリを利用します。
*3
pip install gensim
でgensimをインストールすることが出来ます。

次のコードをコピペして実行して下さい。

from gensim.models import word2vec
import logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO) # 今どれくらい処理が進んでるか確認する用
sentences = word2vec.Text8Corpus('wakati_kankore.txt')
model = word2vec.Word2Vec(sentences, size=200) #MBAだと100MBで2分弱くらいかかりました

def s(posi, nega=[], n=5):
    cnt = 1
    result = model.most_similar(positive = posi, negative = nega, topn = n)
    print '順位', 'キャラ名', '類似度'
    for r in result:
        print cnt, r[0], r[1]
        cnt += 1

これで準備完了!gensimを使うととっても簡単ですね!
関数sの引数は
s([足したい属性], [引きたい属性(省略可。省略時引きたい属性無し)], 上位何個出力するか)
という感じで設定して下さい。
これで意味を計算して類似度が高い順に出力してくれます。

4. word2vecのモデルを利用して加賀さんから乳を引く

早速加賀さん…の前にちょっと霧島で試してみましょう。
霧島は戦艦のメガネ担当です。
艦これはメガネ担当が少なく、
特に霧島は主力を張れる実力かつ委員長タイプという
特異性を持った愛すべき艦娘です。

霧島と類似度が高いキャラ上位5名を上げていきましょう

>>> s(['霧島'])
>順位 キャラ名 類似度
>1 榛名 0.845242
>2 比叡 0.807935
>3 隼鷹 0.696393
>4 鳥海 0.676646
>5 ヒエー 0.668688

1位榛名、2位比叡は姉妹艦+同じ戦艦という艦種でもあり順当。
3位の隼鷹はどういう繋がりかよくわからないですね。
4位の鳥海はメガネ繋がりではないでしょうか。

4位に鳥海が出てきたので、霧島にメガネを足して
戦艦を引いてみるとどうなるか確認します。

>>> s(['霧島','メガネ'],['戦艦'])
>順位 キャラ名 類似度
>1 鳥海 0.507391
>2 深雪 0.49015
>3 比叡 0.482907
>4 文月 0.478213
>5 榛名 0.465617

見事鳥海が1位になりました。
そして先ほどは1位で類似度も非常に高かった榛名が
5位ギリギリまで落ち込んでいるのが面白いですね。
さらに鳥海の艦種である重巡を足してみると…。

>>> s(['霧島','重巡','メガネ'],['戦艦'])
>順位 キャラ名 類似度
>1 鳥海 0.666885
>2 由良 0.635467
>3 高雄 0.62329
>4 利根 0.615573
>5 古鷹 0.61162

鳥海1位は変わらないのですが、類似度がぐっと上がりました。
由良が上がってきてるのはなぜでしょうかね?
そして榛名は完全に落ちました。

色々適当に投げて遊んでみましょう

>>>> s(['おにおこ'])
>順位 キャラ名 類似度
>1 鬼怒 0.635817
>2 荒潮 0.61133
>3 é»’æ½® 0.604449
>4 ひえー 0.603935
>5 カカオ 0.601855

鬼怒(きぬ)はその字面から「おにおこ」
と呼ばれることが多いので狙い通り。

>>>> s(['高雄']) #艦これおっぱい担当。心の底から愛すべきキャラ
>順位 キャラ名 類似度
>1 利根 0.76036
>2 鳥海 0.736499
>3 古鷹 0.729154
>4 愛宕 0.725223
>5 那智 0.718696
>>>> s(['長良']) #艦これスポーツ女子担当。全てを捧げて愛すべきキャラ
>順位 キャラ名 類似度
>1 球磨 0.838549
>2 多摩 0.792809
>3 名取 0.78698
>4 由良 0.742747
>5 羽黒 0.723103
>>>> s(['不知火']) #艦これツン担当。言うまでも無く最も愛すべきキャラ
>順位 キャラ名 類似度
>1 霰 0.791995
>2 é»’æ½® 0.758737
>3 満潮 0.750464
>4 霞 0.748772
>5 荒潮 0.743553

単に2ちゃんねるのテキストを食わせただけで、
艦種メタデータを与えたわけではないのですが、
大体艦種が揃ってますね*4。
ん?なんでこの艦娘を選んだかって?
そうですね、愛かな。

>>>> s(['不幸','姉妹'])
>順位 キャラ名 類似度
>1 鶴 0.691494
>2 扶桑 0.68556
>3 金剛 0.645539
>4 伊勢 0.623382
>5 妹 0.618033

史実、作中台詞、二次創作で何かと不幸に遭遇することから
不幸姉妹と呼ばれる瑞/翔鶴、扶桑。
金剛とか伊勢は不幸と言うか姉妹が強く利いてきたのかなって感じですね。

>>>> s(['提督'])
>順位 キャラ名 類似度
>1 諸氏 0.472251
>2 紳士 0.451628
>3 変態 0.438056
>4 ブルネイ 0.430615
>5 æ–°ç±³ 0.428584

提督同士で呼びかける時よく「提督諸氏」って使うからっぽいですね。
あと3位に変態が来てるんですが皆さんの言動を見るに
これが1位であるべきだと思いましたまる。
もっと良いモデルを作ればきっと一位になるでしょう。



さぁお待ちかね、加賀さんです。

>>>> s(['加賀'])
>順位 キャラ名 類似度
>1 赤城 0.813888
>2 飛龍 0.718207
>3 蒼龍 0.712446
>4 鳳翔 0.675858
>5 祥鳳 0.668783

空母が並んでてまぁ順当な感じです。
ちなみに1位の赤城が0.8超えてて、さらに2位に0.1近い大差つけてるの、
あんまり他で見たこと無いのでよほど頻出な組合せのようですね。

古来よりの言い伝えとして
「ケツの翔鶴、乳の加賀」
という名言があるのは皆さんもご存知の事と思われます。
ではその加賀さんから乳を引いてみたらどうなるでしょうか。

>>>> s(['加賀'],['乳'])
>順位 キャラ名 類似度
>1 赤城 0.492795
>2 飛龍 0.444622
>3 蒼龍 0.436392
>4 瑞鶴 0.411837
>5 Ju 0.408483

結果は、1~3位までは変わらず、4位にこれまでランク外だった瑞鶴が入りました。
1~3位までは加賀さんという属性に寄せられたもので、
そこから乳を引いた結果として寄せられた瑞鶴が
この場合加賀さんの神々しい乳の要素を取り除いた存在と解釈出来ます。
具体的に加賀さん
http://wikiwiki.jp/kancolle/?plugin=ref&page=%B2%C3%B2%EC&src=007.png
と瑞鶴
http://wikiwiki.jp/kancolle/?plugin=ref&page=%BF%F0%C4%E1&src=107.jpg
を見比べてみましょう。
この堅い胸当ての上からでもわかる加賀さん圧倒的な質量を誇る胸、
それに対比すると…いや、その、努力は感じる瑞鶴の胸。はい!

終わりに

なんかおもしろそー!と思って頂ければ幸いです。
word2vecはこれまで出来なかったことを可能にする技術です。
それゆえ今後どのように活用出来るだろうかワクワクがドキドキです。
ただ、まだ出たばかりの技術であるため、知見が殆ど溜まっていません。
あんまりにもデータ依存過ぎる(ちょっと前処理変えるだけで全然結果変わる)し、
結果が信用できるかと言われるとかなり微妙です。
チューニングの仕方も分からず手探りで、
ひたすらモデル作りまくってテストした結果を
目で見比べて良さそうな雰囲気のモデルを選択するという感じで動かしています。
非常にbadです。
だからこそチャンスで、今この技術を使って面白いことしたらワンチャンあるでよ。
ということで、みんなでword2vec触りまくって
「こんなこと出来るよ!」
「こんな使い方どうだろう?」
ってのをやっていければいいなーと思います。

謝辞

ニコニコ学会で発表させて頂きました。
その場で色々コメント頂けて良かったです。
ベストLT有難う御座いました。

追記

f:id:AntiBayesian:20140310003751j:plain
「将来加賀さんに成長する可能性のある駆逐艦を抽出する」
というタスク、面白みあるので誰かやりましょう!!

追記2

「加賀さん - 乳で瑞鶴はおかしい、龍驤が来るべき!」
と主張する提督が多すぎるので説明させて頂きますと、
「巨乳 - 乳 -> 普通乳」
というイメージを持って頂きたい。
私から言えることは以上です。
あと[まな板 -> 龍驤]だったことを最後に付けくわえて締めとさせて頂きます。

*1:ubuntu, macの方がインスコや文字化けの対処本当に楽なので持ってるならそっち使った方が良いです…

*2:私の環境での大体の速度であってきちんとした比較検証を行ったわけではない

*3:google版、macではコンパイル出来たけどwindowsではエラー出まくる上に最終的に動きませんでした…

*4:データと前処理によって結果は大きく変わります。結構頑張らないとこう綺麗な結果は出ないです

*5:全然わからん