Wikificationをしてみよう ~Wikipediaを利用した情報抽出 & 曖昧性解消まで ~

# この記事で紹介すること

- [Wikificationができるパッケージ](https://pypi.python.org/pypi/word2vec-wikification-py)を作ったので紹介
- Wikificationって何？
- Wikificationの利点は？
- どうやって使うの？
- どうやって動作しているの？

# そもそもWikifcationって何よ？？

一言で簡単にまとめると、__テキスト内の単語をWikipediaの記事と関連付ける作業__です。

一例として、このような文があったとしましょう。

`2016年現在出場しているのはヤマハ、ホンダ、スズキ、ドゥカティ、アプリリアの5メーカーと、ワークスマシンの貸与等を受けられるサテライトチームとなっている。`

これは[ロードレース選手権](https://ja.wikipedia.org/wiki/%E3%83%AD%E3%83%BC%E3%83%89%E3%83%AC%E3%83%BC%E3%82%B9%E4%B8%96%E7%95%8C%E9%81%B8%E6%89%8B%E6%A8%A9)からの1節です。

この時、テキスト内に存在している `スズキ` を [スズキ (企業)](https://ja.wikipedia.org/wiki/%E3%82%B9%E3%82%BA%E3%82%AD_(%E4%BC%81%E6%A5%AD)) に結びつける作業があります。
この作業のことを`Wikification`と呼びます。

# Wikificationの利点は？

このウンコ記事を読むよりももっとスマートにメリットをまとめられている[良記事](http://qiita.com/GushiSnow/items/d7c5a09b38d3ca650abd)がありますので、そちらもご覧ください。

### 重要キーワードの抽出

Wikipediaの記事は概ね、__キーワード__と言っても過言ではないでしょう。

先のテキストの例では`2016、ヤマハ、ホンダ、スズキ、ドゥカティ、アプリリア、メーカー、ワークスマシン、貸与`などがWikipediaと関連付けることができます。

`2016`や`貸与`はキーワードなのか？と疑問に思われる方もいらっしゃるかもしれませんが、Wikipedia記事が存在している以上はキーワードとなります。

Wikipediaからゴミワードも含む単語拾って来た後に、うまく処理すれば、キーワード抽出としてはなかなか役に立つのではないでしょうか？

### 語義曖昧性解消

Wikificationの過程では語義曖昧性解消(以下、WSD)も実施されます。
なぜなら、1つの単語が複数の意味を持つことが、実世界では普通にあるからです。

例えば、`きょうはTSUTAYAに行って、つぼみの新作DVDをかりた。`というテキストがあったとしましょう。[^1]

この時、単純なテキストマッチだと、`つぼみ`に曖昧性が発生します。[AV女優のつぼみ](https://ja.wikipedia.org/wiki/%E3%81%A4%E3%81%BC%E3%81%BF_(AV%E5%A5%B3%E5%84%AA)) か[花のつぼみ](https://ja.wikipedia.org/wiki/%E8%95%BE)、はたまた[コブクロの曲](https://ja.wikipedia.org/wiki/%E8%95%BE_(%E3%82%B3%E3%83%96%E3%82%AF%E3%83%AD%E3%81%AE%E6%9B%B2))なのか・・・という複数の可能性が発生します。

もちろん、私たち人間は、「TSUTAYAに行って、DVDをかりているんだから、`つぼみ (AV女優)`だろう！」と文脈から推測できます。
人間の優れた能力ですね。
このように文脈から正しい単語の意味を選択することをWSDと呼びます。
自然言語処理の1研究分野です。

Wikificationは「単語とwikipedia記事の関連付け」の作業の間に、一緒にWSDもやってしまいます。

### 機械学習のための特徴量 

Wikipediaの利点の一つに、__構造化されたデータ__という点があります。
具体的にはカテゴリ体系と記事テンプレートがその役割を果たしています。

カテゴリ体系と記事テンプレートを使えば、ネットワークグラフを構築することができます。
と、いうことは、文書分類や、クラスタリングのタスクに役に立つ情報をとして使えるわけです。

しかし、残念ながら、Wikipediaはこの目的にあまり向いているとは言えません。
その原因としては下記の点が指摘されています。[^3]

- 循環、複数パスが発生しているカテゴリ体系
- 不統一のテンプレート利用

[DBpedia](http://ja.dbpedia.org/)か[WikiData](https://www.wikidata.org/wiki/Wikidata:Main_Page)から発行されているデータの利用を推奨します。[^2]
DBpediaとWikiDataではルールベースではありますが、データクリーニングを実施しています。


# で、どうやって使うのよ？

[Wikificationができるパッケージ](https://pypi.python.org/pypi/word2vec_wikification_py)を作ったわけです。

パッケージ自体は `pip install word2vec-wikification-py` でインストールが走ります。（Python3.5.xでしかテストしていません。）
インストールのために、numpy, gensimあたりが必要なので、Anaconda3の利用をオススメします。

そのあと、 [このスクリプト](https://github.com/Kensuke-Mitsuzawa/word2vec_wikification_py/blob/master/download_model.sh) を `sh download_model.sh` で実行します。
このモデルファイルがないと動きません。

ここからユースケースによって、やることが分岐します。

### 平文状態からWikificationしたい、形態素分割した状態からWikificationしたい

まずは以下の2つが必要になります。

- 形態素分割できる環境
- MysqlとWikipedia dumpデータ

#### 形態素分割環境

もし、形態素分割できる環境が整っていない方は[拙記事](http://qiita.com/Kensuke-Mitsuzawa/items/1d2837b374152c9758c9)を参考程度にご覧ください。

#### MysqlとWikipedia dumpデータの準備

Mysqlのセットアップに関しては、環境によって大きく違うので、なんとも・・・がんばってください！（まるなげ）

Wikipedia dumpデータに関しては、[READMEのこのセクション](https://github.com/Kensuke-Mitsuzawa/word2vec_wikification_py#to-those-who-uses-interfacepredict_japanese_wiki_names)をご覧ください。

#### wikificaionを実施する

`word2vec_wikification_py.interface.predict_japanese_wiki_names_with_wikidump()`の関数を利用します。

戻り値は `word2vec_wikification_py.word2vec_wikification_py.models.SequenceScore` がリストに格納された状態です。
スコアが高い順に「もっともらしいwikipedia記事名の系列」です。

とりあえず、単語の系列が欲しい方は`word2vec_wikification_py.word2vec_wikification_py.models.SequenceScore.get_tokens()`で、単語系列を得ることができます。

詳しくは[example](https://github.com/Kensuke-Mitsuzawa/word2vec-wikification-py/blob/master/examples/ja_example.py)をご覧ください。




### Wikipedia記事名の候補一覧はわかっている。WSDをやりたい。

もしかすると、すでになにかしろの手段でwikipediaの記事候補列挙が終わっている方もいらっしゃるかもしれません。

そのような場合は、次の手順でWSDをします。

1. `word2vec_wikification_py.word2vec_wikification_py.models. WikipediaArticleObject` を生成する
2. モデルファイルの読み込みをする
3. `word2vec_wikification_py.interface. compute_wiki_node_probability()`を呼び出す

#### 候補情報の作成

まずは候補の一覧情報を作成します。
下のコードのように `ヤマハ` の場合は ヤマハ 、それとも ヤマハ発動機 と候補の__wikipedia記事名__を入力します。
この時、__記事名を`[]`で囲うことを忘れないでください。__
`[]`で囲っていないと、著しく精度が低下します。

```py3

seq_wikipedia_article_object = [
            WikipediaArticleObject(page_title='ヤマハ', candidate_article_name=['[ヤマハ]', '[ヤマハ発動機]']),
            WikipediaArticleObject(page_title='スズキ', candidate_article_name=['[スズキ_(企業)]', '[スズキ_(魚)]']),
            WikipediaArticleObject(page_title='ドゥカティ', candidate_article_name=['[ドゥカティ]'])
        ]
```

#### モデルファイルの読み込み

一行で完了です。
モデルファイルは `entity_vector.model.bin` を選択してください。

```py3

model_object = load_entity_model.load_entity_model(path_entity_model=path_model_file, is_use_cache=True)
```

#### インターフェースの呼び出し

`word2vec_wikification_py.interface. compute_wiki_node_probability()` を呼び出して、候補情報とモデルファイルを与えます。

```py3

sequence_score_objects = interface.compute_wiki_node_probability(
          seq_wiki_article_name=seq_wikipedia_article_object,
            entity_vector_model=model_object,
            is_use_cache=True
        )
```

戻り値は `word2vec_wikification_py.word2vec_wikification_py.models.SequenceScore` がリストに格納された状態です。
スコアが高い順に「もっともらしいwikipedia記事名の系列」です。

とりあえず、単語の系列が欲しい方は`word2vec_wikification_py.word2vec_wikification_py.models.SequenceScore.get_tokens()`で、単語系列を得ることができます。


# どうやって動作しているの？

まず大前提として、このパッケージは[日本語Wikipedia エンティティベクトル](http://www.cl.ecei.tohoku.ac.jp/~m-suzuki/jawiki_vector/)の上に成り立っています。
これは東北大乾研究室の鈴木さんの[研究成果](http://www.anlp.jp/proceedings/annual_meeting/2016/pdf_dir/A5-2.pdf)です。このような素晴らしい研究成果を公表している鈴木さんには頭が下がります。

簡潔に日本語Wikipedia エンティティベクトルの役割を説明すると、__「wikipedia記事間のword2vecモデル」__です。
ですので、wikipediaの記事間の類似距離が算出できるようになっているという状態です。


では、「お前は何をやったんや？」という話です。
このパッケージでやっていることは下記の通りです。
1. 入力単語からwikipedia記事候補を作成する
2. 記事候補の組み合わせを使ってグラフを作成する
3. グラフから最適なパスを選び出す（最適なパスの計算に日本語Wikipedia エンティティベクトルを使っています。）

2の工程はMeCabの動作過程をご存知の方ならばイメージできるのではないかと思います。
ちょうどCookpadの技術ブログにMeCabの動作過程を紹介した[良記事](http://techlife.cookpad.com/entry/2016/05/11/170000)があるので、載せておきますね。
この記事で、「ラティス」と呼ばれている構造が、ここで作っているグラフです。

ちなみに、wikipedia記事情報は日本語wikipediaエンティティベクトルモデルの単語情報に依存します。
ですので、2016年後半以降に出現した新しい記事はwikificationの対象外です。
日本語wikipediaエンティティベクトルも更新がされると嬉しいなぁ（```|ω・`）チラ |ω・`）チラ |ω・`）チラ```）

# まとめ

- [Wikificationができるパッケージ](https://pypi.python.org/pypi/word2vec-wikification-py)を作ったよ
- Wikificationができると、キーワード獲得できたり、語義曖昧性解消できたりするお
- 東北大乾研ってやっぱすげーとこだな！
- Wikificationの技術のためにも、Wikipediaへの寄付と記事作成をお願いします。
- バグ、その他は[GithubのIssue](https://github.com/Kensuke-Mitsuzawa/word2vec-wikification-py)にお願いします。

- - -

[^1]: つぼみかわいいですよね(*´ω｀*)
[^2]: WikiDataに関しては、いずれ活用法の記事を書きます。
[^3]: このように書くと「独自研究のおそれがあります。出典を明記してください」とWikipediaの世界では指摘されます。