実況タイムラインとトピックモデルを用いたプリキュアのエピソード間の類似度計算

本記事は[プリキュアAdvent Calendar 2015](http://www.adventar.org/calendars/728)の18日目の記事です。なお本日は12/19ですがプリキュアを愛する皆さんなら海より広い心で許してくれるって私、信じてる！

なお、本記事および本実験はWIPのつもりです。

# Introduction
あのアニメの、あの話とあの話の類似度が計算したい、あるいは類似する話同士でクラスタリングをしたい。そういう時どういう手段があるでしょうか。
一つの手法として、Twitterの実況タイムラインを用いるという事が考えられます。実況タイムラインとは、視聴者がアニメを見ながらその様子や感想をそのままつぶやくものであるため、アニメのエピソードに一対一に対応する、いわばアニメを説明する文書と捉える事ができます。この文書 = アニメ実況タイムライン同士の類似度というのが、エピソード間の類似度の一つの指標として使えるのではないでしょうか。

今回は、この方針でGo!プリンセスプリキュアの各エピソード間の類似度を計算してみたいと思います。
具体的には、トピックモデルの一つであるLDA (Latent Dirichlet Allocation) を用いて、各話の実況タイムライン同士の類似度を計算してみます。

# 使用するツール等
- python
- [gensim](https://radimrehurek.com/gensim/)
- [mecab-ipadic-neologd](https://github.com/neologd/mecab-ipadic-neologd)
- [igraph](http://igraph.org/)

# データ
- 2015/2/1 (第1話) ~ 2015/12/13 (第44話)のTwitterにおけるGo!プリンセスプリキュアの実況タイムライン (タイムラインの記録に失敗した回がいくつかあるので計37話)
- 8:20 ~ 9:30 までの間に`#precure`を付けてつぶやいたものを記録
- リツイートは除外 (元のツイートのみカウント)
- 各回のツイート数は15,000 ~ 48,000 (リツイート除外)
- [mecab-ipadic-neologd](https://github.com/neologd/mecab-ipadic-neologd)で形態素解析
- 「し」「ん」「これ」などと言ったストップワードを除外
- 「プリキュア」「プリンセス」という2つの単語はどの話にも共通する普遍的な単語として考えられるため除外 (これは迷ったけどその方が良い結果を生んだ)

こうした時の単語の出現回数上位20は以下です。

```
きらら 31344
ごきげんよう 25404
人 21358
いい 19218
様 19092
夢 17395
みなみ 17061
はるはる 15956
回 15824
トワ 14579
カナタ 14426
ゆい 13961
クローズ 13844
かわいい 13311
シャット 13049
パフ 11786
なる 11757
変身 10679
見 10342
トゥインクル 9483
```

きらら強し。「プリキュア」「プリンセス」という2つの単語が本来きららよりも上に来ます。

# 実験
## LDAについて
LDAの正しい説明は今の俺には無理だ。でもあなたには[Google](https://www.google.co.jp/search?q=latent+dirichlet+allocation)がある。

用語の説明程度にLDAを解説すると、LDAは文書群から潜在的なトピックを類推します。このトピックとは、例えばニュース記事であれば直感的には「政治」「スポーツ」「美術」などと言ったカテゴリに相当します。
LDAでは、文書は潜在的にそれぞれのトピックを幾ばくかの割合で含んでいることを仮定し、文書をトピックの確率分布として表します。すなわち、ある文書は80%の確率で政治についての話をしており、15%の割合で美術の話をしており、3%の割合でスポーツの話をしており……というふうに捉えます。
また、LDAでは、各トピックは単語の出現確率の分布に相当します。すなわち、「政治」トピックにおいては「オバマ」が7%の確率、「トランプ」が5%の確率、「安倍」が3%の確率……で出現する、といったものです。

プリキュア実況タイムラインに置き換えて、ここからの流れを説明します。
ある回のプリキュア実況タイムラインは、その回を説明する長い文書です。プリキュアには、春野はるかにクローズアップしたシーンや回、いわゆる「はるか回」のように、特定のキャラクターに注目した回があります。以降ではこの「はるか回」や「きらら回」というのがプリキュア実況タイムラインに存在する潜在的なトピックだと仮定して考えていきます。
トピックとは単語の出現確率だと書きました。Go!プリンセスプリキュアの例だと、「きらら」トピックには「トゥインクル」、「ドーナツ」、「ファッション」などといった言葉に高い出現確率が設定されることになります。

まずは、37回に渡るGo!プリンセスプリキュア実況タイムラインの全体を解析し、どういったトピックが存在するかというのを計算してみます。それから、発見したトピックで果たしてそれぞれの回はどの程度「きらら回」だったのか、あるいは「はるか回」だったのか、……あるいは「誰のものでもない回」だったのか、ということを計算していきます。

長々と書きましたが、要は実況タイムライン間の類似度を計算する上で、「はるか回」度、「みなみ回」度、「きらら回」度、「トワ回」度、「誰のものでもない回」度という、直感的でなおかつ少ない指標に落としこむという次元圧縮のための技術として用いています。

LDAの実装としては、[gensim](https://radimrehurek.com/gensim/)というPythonのライブラリを使用しています。

## トピックを抽出
先述したように、LDAは文書群を与えると、その文書群に存在するトピックを類推してくれます。そのトピック数は自ら設定しなくてはなりません。ここでは、Go!プリンセスプリキュア4人それぞれで1トピック、後もう一つどのプリキュアのものでもないトピックを1つと仮定して、トピック数を5に設定します。(はるか回、みなみ回、きらら回、トワ回、誰のものでもない回の想定です)

その結果類推されたトピックは以下です。`数字*単語`というのが先述したトピック内での単語の出現確率です。

```
topic #0 (0.200): 0.009*ごきげんよう + 0.007*トワ + 0.007*人 + 0.006*様 + 0.006*ゆい + 0.005*いい + 0.005*キー + 0.005*変身 + 0.005*夢 + 0.005*スカ ーレット
topic #1 (0.200): 0.009*ゆい + 0.008*クローズ + 0.007*カナタ + 0.007*はるはる + 0.007*夢 + 0.006*回 + 0.006*いい + 0.005*みなみ + 0.005*人 + 0.005* 絶望
topic #2 (0.200): 0.020*きらら + 0.010*ごきげんよう + 0.006*人 + 0.006*いい + 0.006*はるはる + 0.005*夢 + 0.005*トゥインクル + 0.005*クローズ + 0.005*回 + 0.005*かわいい
topic #3 (0.200): 0.014*みなみ + 0.007*はるはる + 0.007*ごきげんよう + 0.006*いい + 0.006*きらら + 0.005*クローズ + 0.005*人 + 0.005*カナタ + 0.005*かわいい + 0.004*様
topic #4 (0.200): 0.010*様 + 0.009*カナタ + 0.008*トワ + 0.008*シャット + 0.007*人 + 0.006*回 + 0.006*ごきげんよう + 0.005*いい + 0.005*夢 + 0.005* みなみ
```

思ったよりそれっぽい。ゆいちゃんが強く現れたのは意外だが実況タイムラインを見ていればなるほどという感じ。
「はるか」、「みなみ」、「きらら」、「トワ」4人が最大の成分になるようにバシッとは決まりませんでしたがしゃーなししゃーなし。

# 類似度
上記トピックを各文書の特徴として(すなわち、各文書を上記5トピックからなる5次元のベクトルとして扱い)、文書間のコサイン類似度を計算します。すると、以下の様な類似度が得られます。

| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 19 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
|---|---|---|---|---|---|---|---|---|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|
|1| |0.315802|0.0|0.0|0.0|0.148118|0.0|0.0|0.0|0.997047|0.108117|0.0|0.0|0.0|0.0|0.0|0.0|0.998236|0.0|1.0|1.0|1.0|0.345272|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|
|2| | |0.116513|0.116513|0.116513|0.854927|0.151135|0.116513|0.472356|0.323976|0.149502|0.116513|0.141464|0.116513|0.116513|0.819519|0.814538|0.363768|0.814538|0.315962|0.315962|0.315962|0.109093|0.245021|0.0|0.814538|0.820534|0.814478|0.544964|0.472356|0.0|0.00903815|0.814489|0.0|0.143125|0.154445|0.816244|
|3| | | |1.0|1.0|0.024152|0.0881911|1.0|0.0|0.0767926|0.989938|1.0|0.999529|1.0|1.0|0.0523216|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.671438|0.0|0.0|0.214036|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.99927|0.998638|0.0154795|
|4| | | | |1.0|0.024152|0.0881911|1.0|0.0|0.0767926|0.989938|1.0|0.999529|1.0|1.0|0.0523216|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.671438|0.0|0.0|0.214036|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.99927|0.998638|0.0154795|
|5| | | | | |0.024152|0.0881911|1.0|0.0|0.0767926|0.989938|1.0|0.999529|1.0|1.0|0.0523216|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.671438|0.0|0.0|0.214036|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.99927|0.998638|0.0154795|
|6| | | | | | |0.00218089|0.0247291|0.0|0.147387|0.0402567|0.0247291|0.055079|0.0247291|0.0247291|0.988927|0.988987|0.204383|0.988987|0.145919|0.145919|0.145919|0.0503817|0.219115|0.0|0.988987|0.971281|0.988914|0.0905681|0.0|0.0|0.0109738|0.988928|0.0|0.0571255|0.0709432|0.989252|
|7| | | | | | | |0.0877574|0.299502|0.00673912|0.1736|0.0877574|0.0877161|0.0877574|0.0877574|0.00459161|0.0|0.0|0.0|0.0|0.0|0.0|0.891625|0.735559|0.950051|0.0|0.0307165|0.0115478|0.298243|0.299502|0.950051|0.949993|0.0104241|0.950051|0.106319|0.109628|0.00135845|
|8| | | | | | | | |0.0|0.0767926|0.989938|1.0|0.999529|1.0|1.0|0.0523216|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.671438|0.0|0.0|0.214036|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.99927|0.998638|0.0154795|
|9| | | | | | | | | |0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.995798|1.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|
|10| | | | | | | | | | |0.182712|0.0756657|0.07563|0.0756657|0.0756657|0.00395895|0.0|0.995374|0.0|0.997133|0.997133|0.997133|0.344283|0.0508048|0.0|0.0|0.0161952|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0756105|0.0755626|0.00117127|
|11| | | | | | | | | | | |0.989787|0.98932|0.989787|0.989787|0.0517872|0.0|0.112216|0.0|0.112415|0.112415|0.112415|0.121087|0.727015|0.087664|0.0|0.212951|0.00106555|0.0|0.0|0.087664|0.0876586|0.00096186|0.087664|0.990783|0.990468|0.0153215|
|12| | | | | | | | | | | | |0.999529|1.0|1.0|0.0523216|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.671438|0.0|0.0|0.214036|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.99927|0.998638|0.0154795|
|13| | | | | | | | | | | | | |0.999397|0.999397|0.0869591|0.0347166|0.00206131|0.0347166|0.0|0.0|0.0|0.0|0.678142|0.0|0.0347166|0.247816|0.034714|0.00317923|0.0|0.0|0.000385217|0.0347145|0.0|0.999806|0.999659|0.0501827|
|14| | | | | | | | | | | | | | |1.0|0.0523216|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.671438|0.0|0.0|0.214036|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.99927|0.998638|0.0154795|
|17| | | | | | | | | | | | | | | |0.0523216|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.671438|0.0|0.0|0.214036|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.99927|0.998638|0.0154795|
|19| | | | | | | | | | | | | | | | |0.998682|0.059297|0.998682|0.0|0.0|0.0|0.0|0.238963|0.0|0.998682|0.986444|0.998608|0.0914558|0.0|0.0|0.0110814|0.998621|0.0|0.0840274|0.0979639|0.999357|
|21| | | | | | | | | | | | | | | | | |0.0593753|1.0|0.0|0.0|0.0|0.0|0.204766|0.0|1.0|0.976745|0.999926|0.0915765|0.0|0.0|0.011096|0.99994|0.0|0.0327753|0.0467628|0.99988|
|22| | | | | | | | | | | | | | | | | | |0.0611948|0.998126|0.998126|0.998126|0.344625|0.0125306|0.0|0.0611948|0.0597717|0.0611903|0.00560401|0.0|0.0|0.000679021|0.0611911|0.0|0.00200568|0.00286164|0.0611875|
|26| | | | | | | | | | | | | | | | | | | |0.0|0.0|0.0|0.0|0.204766|0.0|1.0|0.976745|0.999926|0.0915765|0.0|0.0|0.011096|0.99994|0.0|0.0327753|0.0467628|0.99988|
|27| | | | | | | | | | | | | | | | | | | | |1.0|1.0|0.345272|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|
|28| | | | | | | | | | | | | | | | | | | | | |1.0|0.345272|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|
|29| | | | | | | | | | | | | | | | | | | | | | |0.345272|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|
|30| | | | | | | | | | | | | | | | | | | | | | | |0.668285|0.938327|0.0|0.0117859|0.0114053|0.0|0.0|0.938327|0.938269|0.0102954|0.938327|0.0183955|0.0217185|0.0|
|31| | | | | | | | | | | | | | | | | | | | | | | | |0.711055|0.208365|0.356187|0.216992|0.0190813|0.0|0.711055|0.713323|0.216154|0.711055|0.691833|0.696841|0.218735|
|32| | | | | | | | | | | | | | | | | | | | | | | | | |0.0|0.0125606|0.012155|0.0|0.0|1.0|0.999938|0.0109721|1.0|0.0196045|0.023146|0.0|
|33| | | | | | | | | | | | | | | | | | | | | | | | | | |0.976745|0.999926|0.0915765|0.0|0.0|0.011096|0.99994|0.0|0.0327753|0.0467628|0.99988|
|34| | | | | | | | | | | | | | | | | | | | | | | | | | | |0.976811|0.0894461|0.0|0.0120418|0.0228789|0.97681|0.0120418|0.246198|0.259767|0.979934|
|35| | | | | | | | | | | | | | | | | | | | | | | | | | | | |0.0915719|0.0|0.0101176|0.0212125|1.0|0.0101176|0.032972|0.0469946|0.999829|
|36| | | | | | | | | | | | | | | | | | | | | | | | | | | | | |0.995697|0.0|0.0010282|0.0926584|0.0|0.00303709|0.00433322|0.0926529|
|37| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |0.0|0.0|0.0|0.0|0.0|0.0|0.0|
|38| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |0.999938|0.0109721|1.0|0.0196045|0.023146|0.0|
|39| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |0.0226113|0.999932|0.0199847|0.0236888|0.0116392|
|40| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |0.0120332|0.0330089|0.0470379|0.999808|
|41| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |0.0196045|0.023146|0.0|
|42| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |0.999905|0.0490662|
|43| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |0.0620762|

微妙かも。0.0とか0.99とかピーキー過ぎやしないか。

# ネットワークを描いてみる
上記類似度を利用して、文書間のネットワークを描いてみます。ここでは、類似度が閾値0.99以上の文書間にエッジを張り、構成されるネットワークを力学グラフに起こしてみます。
また、各ノードには私の判断で「はるか回」、「みなみ回」、「きらら回」、「トワ回」、「それ以外」のラベルを付け、それぞれピンク、青、黄色、赤、白の色を付けました。同じ人の回同士がネットワーク的に近いと嬉しいわけです。

ネットワークの構築、描画にはPythonのライブラリの[igraph](http://igraph.org/)を使用しています。

![graph_kk.png](https://qiita-image-store.s3.amazonaws.com/0/53690/f55da05b-ac9b-33ac-4575-a9cad8994d24.png)

黄色と白のまとまりが強いっぽいのは嬉しい。しかし他ははっきりせず微妙なところ。「きらら」は出現回数も多いし、きららトピックは他に比べて強く表れやすいのかもしれない。

# 結論
**微妙な結果。〜 完 〜**
結果が振るわないのには以下の様な理由が考えられます。

- 文書数が少ない。LDAは通常4桁, 5桁というオーダーの文書数で用いられるもので、37という文書数は圧倒的に少ない。そのために今回は計算のパス数を増やしたが、これについては揺らぎを持たせつつ複製した文書を混ぜ込んで水増しするなどという対策などが考えられる。
- 類似度計算が変かも。流石に0.0とか0.99とかピーキー過ぎる気がします。

今回の実験そのものは取り立てて良い結果ではありませんが、「アニメ実況タイムラインからアニメのエピソードについて類推する」という方針は面白いと個人的には考えています (これはスポーツに関しては既に研究があるためそう新しいというわけではないのですが)。今回の結果を見直しつつ今後もこの辺りのことを何かやり続けていく所存です。