複数の形態素解析器を見比べる

# TL;DR

## 更新情報

- kytea, juman, juman++の解析結果を追加しました (2016/10/15)
- 色々な分かち書き結果を冒頭に加えました　(2016/02/28)

この記事を見ると, こんなことができるようになるよ. 便利！！！

```
$ cat text.txt | mecab-all
IPADIC  :私大 ファン な ん です
JUMAN   :私大 ファン な んです
JUMANDIC:私大 ファン な んです
JUMANPP :私大 ファン な んです
KYTEA   :私大 ファン な ん で す
NEOLOG  :私大 ファン な ん です
SNOW    :私大ファン な ん です
UNIDIC  :私大 ファン な ん です

IPADIC  :すもも も もも も もも の うち
JUMAN   :すもも も もも も もも の うち
JUMANDIC:すもも も もも も もも の うち
JUMANPP :すもも も もも も もも の うち
KYTEA   :すもも も も も も も もの うち
NEOLOG  :すもももももももものうち
SNOW    :すもも も もも も もも の うち
UNIDIC  :すもも も もも も もも の うち

IPADIC  :よ の なか ね かお か お かね か な の よ
JUMAN   :よのなか ね かお か お かね か な の よ
JUMANDIC:よのなか ね か お かお かね かな の よ
JUMANPP :よのなか ね かおかお か ね か な の よ
KYTEA   :よ の なか ね か お か お か ね か な の よ
NEOLOG  :よのなか ね かお か おかね か な の よ
SNOW    :よ の なか ね かお か おかね か なの よ
UNIDIC  :よ の なか ね かお か お かね か な の よ

IPADIC  :は は は は は じょうぶ だ
JUMAN   :はは は は は じょうぶだ
JUMANDIC:は は は は は じょうぶだ
JUMANPP :はは は は は じょうぶだ
KYTEA   :ははははは じょうぶ だ
NEOLOG  :は は は は は じょうぶ だ
SNOW    :はははは は じょうぶ だ
UNIDIC  :はははは は じょうぶ だ

IPADIC  :ぶた が ぶた を ぶっ た ので 、 ぶた れ た ぶた が ぶっ た ぶた を ぶっ た 。
JUMAN   :ぶた が ぶた を ぶった ので 、 ぶた れた ぶた が ぶった ぶた を ぶった 。
JUMANDIC:ぶた が ぶた を ぶった ので 、 ぶた れた ぶた が ぶった ぶた を ぶった 。
JUMANPP :ぶた が ぶた を ぶった ので 、 ぶた れた ぶた が ぶった ぶた を ぶった 。
KYTEA   :ぶ た が ぶた を ぶ っ た の で 、 ぶた れ た ぶ た が ぶ っ た ぶた を ぶ っ た 。
NEOLOG  :ぶた が ぶた を ぶっ た ので 、 ぶた れ た ぶた が ぶっ た ぶた を ぶっ た 。
SNOW    :ぶた が ぶた を ぶっ た ので 、 ぶた れ た ぶた がぶっ た ぶた を ぶっ た 。
UNIDIC  :ぶた が ぶた を ぶっ た の で 、 ぶた れ た ぶた がぶっ た ぶた を ぶっ た 。

IPADIC  :形態素 解析 なう
JUMAN   :形態 素 解析 なう
JUMANDIC:形態 素 解析 なう
JUMANPP :形態 素 解析 なう
KYTEA   :形態 素 解析 な う
NEOLOG  :形態素解析 なう
SNOW    :形態素解析なう
UNIDIC  :形態 素 解析 なう

IPADIC  :けん さく えんじん ぐ ー ぐる
JUMAN   :けんさく えんじん ぐー ぐる
JUMANDIC:けんさく えんじん ぐ ー ぐる
JUMANPP :けんさく えんじん ぐーぐる
KYTEA   :けんさく えんじ ん ぐーぐる
NEOLOG  :けんさ くえん じん ぐー ぐる
SNOW    :けんさくえんじん ぐー ぐる
UNIDIC  :けんさく えんじん ぐー ぐる

IPADIC  :駐 在所 なう
JUMAN   :駐在 所 なう
JUMANDIC:駐在 所 なう
JUMANPP :駐在 所 なう
KYTEA   :駐在 所 な う
NEOLOG  :駐在所 なう
SNOW    :駐在所なう
UNIDIC  :駐在 所 なう

IPADIC  :外国 人参 政権 は 難しい 問題 だ
JUMAN   :外国 人参 政権 は 難しい 問題 だ
JUMANDIC:外国 人参 政権 は 難しい 問題 だ
JUMANPP :外国 人 参政 権 は 難しい 問題 だ
KYTEA   :外国 人 参政 権 は 難し い 問題 だ
NEOLOG  :外国人参政権 は 難しい 問題 だ
SNOW    :外国人参政権 は 難しい 問題 だ
UNIDIC  :外国 人参 政権 は 難しい 問題 だ

IPADIC  :ああ ああ ああ あー いい な ーーーー
JUMAN   :ああ ああ ああ あー いい なーーーー
JUMANDIC:ああ ああ ああ あー いい な ーーーー
JUMANPP :ああ ああ ああ あーい い なーーーー
KYTEA   :あああああああー い い なーー ー ー
NEOLOG  :ああああああ あー いい な ーーーー
SNOW    :ああ ああ ああ あーいい なー ー ー ー
UNIDIC  :ああ ああ ああ あー いい なー ー ー ー

IPADIC  :手前味噌 で 悪い が 、 雪だるま も 頑張っ てる よ ！
JUMAN   :手前 味噌 で 悪い が 、 雪だるま も 頑張って る よ ！
JUMANDIC:手前 味噌 で 悪い が 、 雪だるま も 頑張って る よ ！
JUMANPP :手前 味噌 で 悪い が 、 雪だるま も 頑張って る よ ！
KYTEA   :手前 味噌 で 悪 い が 、 雪 だるま も 頑張 っ て る よ ！
NEOLOG  :手前味噌 で 悪い が 、 雪だるま も 頑張っ てる よ ！
SNOW    :手前味噌 で 悪い が 、 雪だるま も 頑張っ てる よ ！
UNIDIC  :手前 味噌 で 悪い が 、 雪 だるま も 頑張っ てる よ ！

IPADIC  :ロース 肉薄 切り を ボール の 中 に 入れ ます
JUMAN   :ロース 肉 薄切り を ボール の 中 に 入れ ます
JUMANDIC:ロース 肉 薄切り を ボール の 中 に 入れ ます
JUMANPP :ロース 肉 薄切り を ボール の 中 に 入れ ます
KYTEA   :ロース 肉 薄切り を ボール の 中 に 入れ ま す
NEOLOG  :ロース 肉薄 切り を ボール の 中 に 入れ ます
SNOW    :ロース肉薄切り を ボール の 中 に 入れ ます
UNIDIC  :ロース 肉薄 切り を ボール の 中 に 入れ ます

IPADIC  :りん ご ジュース は おいしい
JUMAN   :りんご ジュース は おいしい
JUMANDIC:りんご ジュース は おいしい
JUMANPP :りんご ジュース は おいしい
KYTEA   :りんご ジュース は おいし い
NEOLOG  :りんごジュース は おいしい
SNOW    :りんごジュース は おいしい
UNIDIC  :りんご ジュース は おいしい

IPADIC  :ほこり が き に なる
JUMAN   :ほこり がき に なる
JUMANDIC:ほこり がき に なる
JUMANPP :ほこり がき に なる
KYTEA   :ほこり が き に な る
NEOLOG  :ほこり が き に なる
SNOW    :ほこり が き に なる
UNIDIC  :ほこり が き に なる

IPADIC  :首相 撲殺 事件
JUMAN   :首 相撲 殺 事件
JUMANDIC:首相 撲殺 事件
JUMANPP :首 相撲 殺 事件
KYTEA   :首相 撲殺 事件
NEOLOG  :首相 撲殺 事件
SNOW    :首相撲殺事件
UNIDIC  :首相 撲殺 事件

IPADIC  :この 先 生き のこる
JUMAN   :この先 生きのこる
JUMANDIC:この先 生きのこる
JUMANPP :この先 生きのこる
KYTEA   :この 先生きのこ る
NEOLOG  :この 先生きのこる
SNOW    :この 先 生きのこる
UNIDIC  :この 先 生きのこる

IPADIC  :宿題 も やっと する
JUMAN   :宿題 も やっと する
JUMANDIC:宿題 も やっと する
JUMANPP :宿題 も やっと する
KYTEA   :宿題 も やっと する
NEOLOG  :宿題 も やっと する
SNOW    :宿題 も やっと する
UNIDIC  :宿題 も やっと する

IPADIC  :宿題 も もやっ と する
JUMAN   :宿題 もも やっと する
JUMANDIC:宿題 もも やっと する
JUMANPP :宿題 も もやっと する
KYTEA   :宿題 も も やっと する
NEOLOG  :宿題 も もやっ と する
SNOW    :宿題 も も やっと する
UNIDIC  :宿題 も も やっと する

IPADIC  :なにか もやっ と する
JUMAN   :なに かも やっと する
JUMANDIC:なに かも やっと する
JUMANPP :なに かも やっと する
KYTEA   :なに か も やっと する
NEOLOG  :なにか もやっ と する
SNOW    :なにか も やっと する
UNIDIC  :なに か も やっと する

IPADIC  :この 本気 に なっ て た 。
JUMAN   :この 本気に なって た 。
JUMANDIC:この 本気に なって た 。
JUMANPP :この 本気に なって た 。
KYTEA   :この 本気 に な っ て た 。
NEOLOG  :この 本気 に なっ て た 。
SNOW    :この 本気 に なっ て た 。
UNIDIC  :この 本気 に なっ て た 。

IPADIC  :新米 大統領
JUMAN   :新米 大統領
JUMANDIC:新米 大統領
JUMANPP :新米 大統領
KYTEA   :新米 大統領
NEOLOG  :新米 大統領
SNOW    :新米大統領
UNIDIC  :新米 大統領

IPADIC  :関西国際空港 駅 に 行く
JUMAN   :関西 国際 空港 駅 に 行く
JUMANDIC:関西 国際 空港 駅 に 行く
JUMANPP :関西 国際 空港 駅 に 行く
KYTEA   :関西 国際 空港 駅 に 行 く
NEOLOG  :関西国際 空港駅 に 行く
SNOW    :関西国際 空港 駅 に 行く
UNIDIC  :関西 国際 空港 駅 に 行く

```

__DISCLAIMER__
書かれている内容は記事の洗練のため随時変更されますので, 
この内容を実行したからといって不利益を被っても責任はとれません.
何か問題・訂正等がありましたら随時受け付けます.


# 形態素解析の闇
「固有名詞がうまく分割されない」
「Unidicとかipadicとかどれ使えばわからない」
「neologd！ neologd！」
「辞書何それ？ おいしいの(^q^)」
「kuromoji！ kuromoji！」

みなさん、その**形態素解析結果** ちゃんと見比べたことありますか？？？

meacb, kuromoji,kagome,janome といった形態素解析ツールを使ってる方、
__「形態素解析」__ で大事なのは__「辞書」__です.

「辞書」がテキストが出現可能な単語を全て決めます。
「辞書」に無い単語はどんなに頑張っても出現しません。
「辞書」に単語があっても,計算上絶対に解析結果に反映されない語も大量にあります
(「辞書を充実」させても, 学習データにそのエントリが使われる文がなければ意味が無い)

もしかして、あなたが今, 直面している問題は
__「あながた利用している形態素解析辞書が悪い」__せいかもしれません！！！

# 辞書毎に「mecab-○○○」を用意する

インストールの方法とか初期設定については
他に記事があるので、そちらに譲ります.

細かい説明は省きますが, mecabではカスタマイズ可能な辞書を用意することで
解析単位を自由に変えることができます。
(改造しすぎて, 形態素とは何だったのか...)

主なものにipadic, unidic, juman(JUMANから辞書だけもってきたもの)とかあります.
-d オプションでこれらのシステム辞書のディレクトリ参照先が指定できるので,
簡単に切り替えられるようになっています.

使いやすくするためには, 辞書毎にコマンド化してしまいましょう。
そして, パスの通る位置に置きましょう

例えば, unidic単位で単語分割したいときには
こんな形でコマンド化しています(zshを利用している方はエイリアスを貼っても良いと思います).

```sh:mecab-unidic
#!/bin/sh
/tools/env/bin/mecab -d /tools/src/mecab-dics/unidic-mecab-2.1.2_src $@
```
mecab用のオプションも そのまま扱えます。

```sh
$ echo '辞書ごとにコマンドかしてしまいましょう！' | mecab-unidic　 -Owakati
辞書 ごと に コマンド 化 し て しまい ましょ う ！
```

# 複数の形態素解析結果を 合わせてみたい
複数の形態素解析結果を見比べれるコマンドがあると ものすごい便利です.
ここからシェル芸(zsh便利ですね)になります...

zshの便利なプロセス置換を利用すると, 冒頭のコマンドが簡単に実装できます.
sortを使ってしまうので使わないうまい書き方があるかもしれません（他に良いアイディアがあれば教えてください）

```zsh
#!/usr/env zsh
cat -  | { \
 > >(mecab-juman -Owakati | sed 's/^/JUMAN\t:/' | nl) \
} | sort | cut -f2- | sed 's/^IPADIC/\n&/' | sed '1d'
```

## コマンドの実装の詳細
zshには出力を分岐する機能(プロセス置換:PROCESS SUBSTITUION)があります(teeのようなイメージ).
上のコマンドの説明をすると, 

```zsh
> >(mecab-ipadic-neologd -Owakati | sed 's/^/NEOLOG\t:/' | nl) \
```
の部分が, 解析したい辞書のひとまとまりになっています.
- `mecab-ipadic-neologd -Owakati`が形態素解析 mecab-ipadic-neologd のコマンドです.
- `sed 's/^/NEOLOG\t:/'`で辞書毎にラベルをつけます.
- `nl` は 文番号を付与するために使います(grep -n ''の方が整形はしやすそう)
- `sort | cut -f2- | sed 's/^IPADIC/\n&/' | sed '1d'` で出力結果を言い感じにまとめてます.

これを用意したコマンドの数だけ繋げることで, 複数の解析結果を比較するコマンドの完成です!!
これを比較したい辞書の数だけ書いてしまいましょう！！！

こんな感じです。

```zsh:mecab-all
#!/usr/bin/zsh
cat -  | { \
 > >(mecab-ipadic-neologd -Owakati | sed 's/^/NEOLOG\t:/' | nl) \
 > >(snowman -w | sed 's/^/SNOW\t:/' | nl) \
 > >(juman | juman_wakati | sed 's/^/JUMAN\t:/' | nl) \
 > >(docker run -i --rm yamitzky/jumanpp | juman_wakati | sed 's/^/JUMANPP\t:/' | nl) \
 > >(mecab-juman -Owakati | sed 's/^/JUMANDIC:/' | nl) \
 > >(mecab-unidic -Owakati | sed 's/^/UNIDIC\t:/' | nl) \
 > >(mecab-ipadic -Owakati | sed 's/^/IPADIC\t:/' | nl) \
 > >(kytea -notags | sed 's/^/KYTEA\t:/' | nl) \
} | sort | cut -f2- | sed 's/^IPADIC/\n&/' | sed '1d'
```
※ kyteaは[こちら](http://www.phontron.com/kytea/index-ja.html)で公開されている単語分割/品詞・読み推定用のソフトウェアです
※ juman/jumanpp　は京都大学の黒橋・河村研究室で作成された形態素解析器です[juman](http://nlp.ist.i.kyoto-u.ac.jp/index.php?cmd=read&page=JUMAN&alias%5B%5D=%E6%97%A5%E6%9C%AC%E8%AA%9E%E5%BD%A2%E6%85%8B%E7%B4%A0%E8%A7%A3%E6%9E%90%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0JUMAN)
※ jumanppは[docker](https://hub.docker.com/r/yamitzky/jumanpp/)を利用しています
※ snowmanは 長岡技術科学大学で開発している[単語解析器「雪だるま」](http://snowman.jnlp.org/snowman)のwakati用のラッパーです.
表記揺れと慣用句に向いている解析器です.ステマです.

## 作ったコマンドで違いを見てみる
このコマンドで
色々解析結果を見比べてみましょう！！

```
$ cat hoge.txt | mecab-all
IPADIC  :1 . 京都大 学 に 行く
JUMAN   :1 . 京都 大学 に 行く
NEOLOG  :1 . 京都大 学 に 行く
SNOW    :1 . 京都大学 に 行く
UNIDIC  :1 . 京都 大学 に 行く

IPADIC  :足下 を 見 ない で ほしい 。
JUMAN   :足下 を 見 ないで ほしい 。
NEOLOG  :足下 を 見 ない で ほしい 。
SNOW    :足下を見 ない で ほしい 。
UNIDIC  :足下 を 見 ない で ほしい 。

IPADIC  :mecab は やっぱ いい よ ね ！
JUMAN   :mecab は やっぱ いい よ ね ！
NEOLOG  :mecab は やっぱ いい よ ね ！
SNOW    :mecab は やっぱいい よ ね ！
UNIDIC  :mecab は やっぱ いい よ ね ！

IPADIC  :手前味噌 で 悪い が 、 雪だるま も まだまだ 負け ない
JUMAN   :手前 味噌 で 悪い が 、 雪だるま も まだまだ 負け ない
NEOLOG  :手前味噌 で 悪い が 、 雪だるま も まだまだ 負け ない
SNOW    :手前味噌 で 悪い が 、 雪だるま も まだまだ 負け ない
UNIDIC  :手前 味噌 で 悪い が 、 雪 だるま も まだまだ 負け ない

IPADIC  :zsh が 使えれ ば 鬼 に 金棒 だ ！
JUMAN   :zsh が 使えれば 鬼 に 金 棒 だ ！
NEOLOG  :zsh が 使えれ ば 鬼に金棒 だ ！
SNOW    :zsh が 使えれ ば 鬼に金棒 だ ！
UNIDIC  :z s h が 使えれ ば 鬼 に 金棒 だ ！

IPADIC  :外国 人参 政権 は 難しい 議題 だ 。
JUMAN   :外国 人参 政権 は 難しい 議題 だ 。
NEOLOG  :外国人参政権 は 難しい 議題 だ 。
SNOW    :外国人参政権 は 難しい 議題 だ 。
UNIDIC  :外国 人参 政権 は 難しい 議題 だ 。
```

- neologdは慣用句とかも良い感じにまとめてくれますね. 良いですね.
- 「雪だるま」では 「慣用句」をうまく一つにまとめてくれます(「足下を見/ない/で/ほしい。」 )

# 結論

- 便利でよく使う処理はコマンド化しましょう（ので良いコマンドあれば教えてください...）  
- 複数の解析結果をみれるようにすると超べんり！！！
- zshのシェル芸すごい！！

#付録

## zsh芸の問題点
- sortしてしまっているので テキストを全て解析してから出力するのでレスポンスが遅い.
- 改良案とかお待ちしています！


## python 実装
ちなみにpythonで書くとこんな感じになります(これをzshでは1行で書けるのだからzshはクールですよ)
※ただし標準入力を全て読み切ってから出力する形態素解析はこのスクリプトではうまく動きません

```py3:mecab-all
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import shlex
import subprocess

commands = [
    ('NEOLOG', 'mecab-ipadic-neologd -Owakati'),
    # ('SNOWMAN', 'snow-wakati -Owakati'),
    ('JUMAN', 'mecab-juman -Owakati'),
    ('UNIDIC', 'mecab-unidic -Owakati'),
    ('IPADIC', 'mecab-ipadic -Owakati'),
]

procs = [ (name, subprocess.Popen(
    shlex.split(cmd),
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    shell=False,
)) for name, cmd in commands]


for line in sys.stdin:
    for name, p in procs:
        p.stdin.write(line.encode('utf-8'))
        p.stdin.flush()
        print('{:10}:{}'.format(name, p.stdout.readline().decode('utf8')), end='')

    print()
```