読者です 読者をやめる 読者になる 読者になる

おいしいとこはすこしだけ

文系出身SE見習いの備忘録。

Doc2VecでMTGの類似カードを探してみた

文系出身SE見習いの北白川キリコです。


先月やりかけてた、MTGのカードデータと機械学習で何かできないかなーというのをようやく進めました。

先月の段階でWisdom Guildのテキストデータから必要な情報を抽出して形態素解析するところまでできていたので、今日はとりあえずそこからカード名とカードテキストだけ取り出してDoc2Vecで遊んでみました。


Doc2Vecとは

gensimのモジュールの1つです。

Word2Vecを提唱したGoogleのMikolovさんが、「Word2Vecを応用して単語だけじゃなくて文章もベクトル化できるんじゃない?」ということでParagraph2Vecというのを考えてくれました。

Doc2Vecは、その論文をもとに実装されたモジュールとのことです。(Mikolovさん自身が書いたソースコードは公開されていません)

gensim: models.doc2vec – Deep learning with paragraph2vec

gensimはCythonを使っているのでメッチャ早い!! chainerなら1億年ぐらいかかる*1ところを1分で処理してれます。


データ前準備

  • card_names.txt:カード名を改行区切りで記述したもの
  • card_text.txt:カードテキストを形態素解析したトークンを、半角スペース区切りで各カード1行になるよう記述したもの

カード名とカードテキストの順番が一致するようにする。

ただ、Janomeの簡易ユーザ辞書だと優先度を付けられないせいか、辞書登録しても複合語が分割されちゃってたりするんですよね……(「絆」「魂」とか)

この問題に関しては今後検討が必要。


Doc2Vecを動かしてみる

こちらを参考にさせていただきました。

ノート/テキストマイニング/Doc2Vecを試す - 東邦大学理学部情報科学科 山内のサイト


from gensim.models import doc2vec

# カードテキスト読み込み
card_text = doc2vec.TaggedLineDocument('card_text.txt')

# カード名前読み込み(結果表示に使用する)
with codecs.open('card_name.txt', 'r', encoding='utf-8') as f:    
    card_names = [card_name.replace('\n', '') for card_name in f.readlines()]

# モデルデータ作成
# sizeはベクトル圧縮時の次元数
# windowは解析時に対象単語の前後何単語まで見るか
# min_countは出現回数が何回以下の単語を無視するか
# workerはスレッド数
model = doc2vec.Doc2Vec(card_text, size=100, window=8, min_count=2, workers=4)

# データ保存
model.save('mtg.model')
model.save_word2vec_format('mtg.w2vmodel')


#ここから単語同士の類似度

word = u'飛行' # 類似単語を求めたい単語
print word + ' is similar to...'
# 類似単語と類似度のタプル(類似度上位10件)のリストを受け取る
for similarity in model.most_similar(positive=word):
    # タプルのままIPythonに出力するとリテラル表示されないのでこの書き方
    print similarity[0], similarity[1]

# 飛行 is similar to...
# トランプル 0.677506804466
# 速攻 0.510393500328
# 警戒 0.468019366264
# World 0.467057049274
# of 0.449396759272
# は 0.437647610903
# 細工 0.437286615372
# 呪術 0.430927336216
# 合う 0.42149746418
# 占 0.417448014021


# ここからカード同士の類似度

test_card_name = u'精神を刻む者、ジェイス' # 類似カードを求めたいカード名
card_index = card_names.index(test_card_name)

# 類似カードと類似度のタプル(類似度上位10件)のリストを受け取る
similar_docs = model.docvecs.most_similar(card_index)
print name_list[card_index] + ' is similar to...'
for similar_doc in similar_docs:
    print name_list[similar_doc[0]], similar_doc[1]

# 精神を刻む者、ジェイス is similar to...
# ジェイス・ベレレン 0.695143640041
# 解放された者、カーン 0.653617322445
# ゴルガリの凶漢 0.620760858059
# ヴェールのリリアナ 0.608255207539
# リリアナ・ヴェス 0.570708036423
# 屑鉄の学者、ダレッティ 0.563854336739
# 根囲い 0.533906698227
# ゴブリンの手投げ弾 0.528164923191
# 卑小な回収者 0.525354683399
# 威圧ドローン 0.524666070938

うーん。類似単語は正直微妙ですね。

類似カードはまあまあそれっぽいのが出てるのかな。多分プレインズウォーカーは文体が似てるんでしょうね。


他には、

耕作 is similar to...

我が威厳に相応しき領地 0.56421905756

分かれ道 0.517223894596

ウスーンのスフィンクス 0.4909247756

水晶のしぶき 0.488548845053

イロアスの武器庫 0.483968704939

ナイレアの試練 0.474029809237

はるかなる放浪 0.472717642784

炬火のチャンドラ 0.47109413147

非道の総督 0.466766059399

家畜化 0.463470190763

まあ確かに似てはいるか。


霧を歩むもの、ウリル is similar to...

道教の隠者 0.686899602413

果てしなきもの 0.671681404114

追われる足跡 0.65790194273

恐慌の呪文爆弾 0.642627716064

発掘 0.633514404297

夜鷹 0.631523430347

潜む者 0.622953295708

シェオルドレッドの刈り取るもの 0.622068822384

無慈悲なる者ケアヴェク 0.612911939621

防護の泡 0.612293899059

うーん、これはよく分からない。とりあえず呪禁が拾われてるっぽいけど。


囁く者、シェオルドレッド is similar to...

疫病甲虫 0.648859977722

遠沼の探検者 0.644255161285

湿地のゴブリン 0.580218136311

奪い取り屋、サーダ・アデール 0.574257850647

巨人釣り 0.570150911808

鏡の大魔術師 0.556969940662

迷える魂 0.553947329521

野生の雄牛 0.537679135799

稲妻の鉤爪 0.528969883919

略奪する夜魔 0.525935411453

沼を渡る者、シェオルドレッドさん!!!!


ということで、まあなんとなーく似てはいるけどまだ似たカードとは言えないかなあ。

形態素解析の辞書の問題をクリアして、あとはパラメータ調整でもうちょっと精度を上げたいところです。

取り敢えず今日はここまで。


※追記(8/21):精度上がりました

kitashirakawakiriko.hatenablog.com


そういえば最近読んだ本

今更なラインナップを読んでます!

何者 (新潮文庫)

何者 (新潮文庫)

どっちも面白かった!!

*1:1億年は盛りすぎです。70倍ぐらいだそうです。