Mozcの辞書を使ってMeCabでかな漢字変換する

Mozc (OSSのIME) 用の辞書をMeCab (OSSの形態素解析器) 用の辞書に変換することで、MeCabでかな漢字変換できるようにするスクリプトをお遊びで作りました。
💁‍♀ https://github.com/ikegami-yukino/mecab-as-kkc 💁‍♂

現状では、かな漢字変換は日常的に使われているにも関わらず割とニッチな分野です。特にLinux界隈ではこれまで使われてきたMozcの開発頻度が大幅に下がったため、新しいIMEの登場が期待されています。これをきっかけに少しでもかな漢字変換に興味を持っていただければ幸いです。もっと欲を言えばMozcの代わりとなる新しいLinux用IMEを作っていただけたら最高です。

また、mecab-as-kkcを[nksnd](https://github.com/yoriyuki/nksnd)や[JLM](https://github.com/jiali-ms/JLM)、[SIMPLE](http://www.ar.media.kyoto-u.ac.jp/mori/research/topics/KKC/)、[ngram-converter-cpp](https://github.com/hiroshi-manabe/ngram-converter-cpp)、[neural_ime](https://github.com/yohokuno/neural_ime)、[mecab-skkserv](http://chasen.org/~taku/software/mecab-skkserv/)などと比較してみるのも面白いかと思います。

## 背景
すごく雑に言うとMeCabでは`matrix.def` (品詞連接モデル) と`*.csv` (語彙とその生起コストと品詞を含んだ辞書)の2つが解析に大きく貢献しています。同じようにMozcでも`connection.deflate` (品詞連接モデル) と`dictionary*.txt`(語彙とその生起コストと品詞を含んだ辞書)が変換に大きく貢献しています。
これらは役割が似ているので、Mozcの辞書と品詞連接モデルをMeCab用に変換すればMeCabでもかな漢字変換が出来るのではないかという仮説のもとで作りました。

似たようなものとして[mecab-skkserv](http://chasen.org/~taku/software/mecab-skkserv/)がありますが、RWCコーパス (毎日新聞1994年版に形態素情報を付与したコーパス) を大幅に改変したものをベースにして作られた[^1]IPADicを使っているため新語に対応できていないという問題があります。Mozcも現時点では2018年から開発が止まっているのですが、IPADicよりは新しい辞書でありIPADicよりも語彙が豊富 (446,035 < 1,169,217) という点でメリットがあります。(一方でMozcは機械的に作られたような不自然なエントリが混じっているというデメリットがあります)

もっと似てるものとして[akirakuboさんのmecab-mozcdic](https://github.com/akirakubo/mecab-mozcdic)がありますが、わたしのはファイル変換スクリプトを提供しているのでどういう処理を行って生成しているのかわかりやすい点と`dicrc`ファイルにいくつかかな漢字変換用の出力フォーマットを定義している点 (下記使用例のところを参照) が異なります (作ったあとに存在に気づいた……💧) (気づいてたらわざわざ自分で作らなかったかも)

## 品詞連接モデルと辞書について雑な説明

品詞連接モデルは文脈Aのあとには文脈Bになりやすい、たとえば"姓の後には名前が出てきやすい"というようなことをモデル化したもので、辞書はある文脈におけるある語の生起しやすさを表現したものです。MeCabやMozcは主にこれら (これら以外にもあるのですが) を用いてコストが最小になるような組み合わせを探索して解を出します。

## MeCab as KKCはどのように品詞連接モデルや辞書を変換するか
### 品詞連接モデル
Mozcの`connection.deflate`は拡張子のとおりdeflateアルゴリズム (LZ77 + ハフマン符号) で圧縮されています。それを伸長すると以下のようになります。

```
2652
0
5891
4849
4810
5598
...
```
一番上の行は品詞 (活用形含む) の数を表していて、`connection.deflate`の行数は`7033105`で、`2652 (品詞の数) * 2652 (品詞の数) + 1 (一番上の行) = 7033105`であることから正方行列であることがわかります。
それ以降の行はプログラミング言語的に記述するとすれば、

```
matrix[0][0] = 0
matrix[0][1] = 5891
matrix[0][2] = 4849
matrix[0][3] = 4810
matrix[0][4] = 5598
...
```

みたいな感じの行列の値だけをずらーっと並べています。
一方で、MeCabのmatrix.defは下記のようになっています。

```
1316 1316
0 0 -434
0 1 1
0 2 -1630
0 3 -1671
0 4 24
...
```
Mozcと似たように一番上の行は品詞 (活用形含む) の数で、それ以降の行は[右文脈ID 左文脈ID コスト]となっています。
なので以下のように簡単に変換できます。

```
2652 2652
0 0 0
0 1 5891
0 2 4849
0 3 4810
0 4 5598
...
```

### 辞書
Mozcのtsv形式のファイルをcsv形式に変換するだけです。つまりTAB文字を,に変換するだけ。
注意してほしいのが、Mozcの辞書には","というreadingを持つエントリが存在していることです。今回の目的はひらがなをかな漢字混じりの文字列に変換することなので"、"を打つことはあっても","を打つことはないと想定して除外しました。

## 使い方
### 用意するもの
- Git
- MeCab
- Python 3

### 準備

```
$ git clone --depth 1 https://github.com/ikegami-yukino/mecab-as-kkc.git
```
### ビルド

```
$ make
```

### インストール

```
$ make install
```
or

```
$ cp -r maceb-as-kkc <target directory>/maceb-as-kkc
```

もし辞書にエントリを追加する予定がない場合は、`lex.csv`と`matrix.def`を削除すると約160MBほどディスクスペースが空きます。

```
$ rm `mecab-config --dicdir`/mecab-as-kkc/lex.csv
$ rm `mecab-config --dicdir`/mecab-as-kkc/matrix.def
```
### アンインストール
```
$ make uninstall
```

or

```
$ rm -r <target directory>/maceb-as-kkc
```

## 使用例

MeCabの`-d`オプションで辞書を指定すると使えます。

### 候補を複数出すかな漢字変換
MeCabの`-N`オプションでN-best解を出すことにより候補を複数出します。

```
$ echo ここではきものをぬぎます | mecab -d `mecab-config --dicdir`/maceb-as-kkc -N 5
ここでは着物を脱ぎます
ここでは着物を脱ぎます
ここではきものを脱ぎます
ここではきものを脱ぎます
ここで履物を脱ぎます
```
### かな漢字変換しつつ分かち書き
```
$ echo あなたはだれ? | mecab -d mecab-as-kkc -Owakachi
あなた は 誰 ? 
```

### 文脈IDを表示
```
$ echo あなたはだれ? | mecab -d mecab-as-kkc -Oid
あなた,1895,1895,あなた
は,283,283,は
だれ,1895,1895,誰
?,2635,2635,?
EOS
```

## 辞書に新しいエントリを追加する方法

ここでは例として `めかぶ` を `和布蕪` に変換出来るようにするための方法を説明します。あくまでも一例に過ぎないので、もちろん他の言葉でも大丈夫です。

### フォーマット
`lex.csv`に1行1エントリの形式で下記のようなフォーマットでエントリを追加することが出来ます。

```
めかぶ,1847,1847,4000,和布蕪
```
左から 読み (ひらがな), 右文脈ID, 左文脈ID, コスト, 単語を示しています。この場合"めかぶ"が"和布蕪"に変換されます。

### 文脈IDを決める
`mozc/src/data/dictionary_oss/id.def`ファイルを見て文脈IDを決めます。

参考までによく使われると思う文脈IDは下記のとおりです。

```
1837 名詞,サ変接続,*,*,*,*,*
1847 名詞,一般,*,*,*,*,*
1916 名詞,固有名詞,一般,*,*,*,*
1917 名詞,固有名詞,人名,一般,*,*,*
1918 名詞,固有名詞,人名,名,*,*,*
1919 名詞,固有名詞,人名,姓,*,*,*
1920 名詞,固有名詞,地域,一般,*,*,*
1925 名詞,固有名詞,組織,*,*,*,*
```

### コストの調整
mecab-skkservと同じようなやり方でいいと思います。

1. とりあえずコストを4000にしてみる
2. 辞書ディレクトリ内で以下のコマンドで辞書をコンパイルし直す
```$ `mecab-config --libexecdir`/mecab-dict-index```

3. 結果を確認
```$ echo めかぶ | mecab -d `mecab-config --dicdir`/maceb-as-kkc```
4. もし"和布蕪"が一番に出なかったら徐々にコストを下げていく ("大幅に"下げると誤変換の原因となるので、時間がかかりますが"徐々に"下げていくことをおすすめします)

読みがめちゃくちゃ長い場合、たとえば"きゃろらいんちゃろんぷろっぷきゃりーぱみゅぱみゅ"みたいなのはどうせ他の語と干渉することはないのでコストは0でもいいと思います。

## 制限
現時点では記号や絵文字の変換には対応していません。
どのように適切なコストを決めればいいかわからないからです。

こうした方がいいよ！って案がある方、Contributions are welcomeです！

## おまけ 名前の由来
最初はマイナーなKKC (Kana-Kanji Converter) という言葉じゃなくて有名なIME (Input Method Editor) という言葉を使おうと考えましたが、IMEというとプリエディット機能 (アルファベット列をひらがなに変換したりとか) やキャッシュ機能が付いてたりGUIから単語を辞書に追加する機能が付いてたりとリッチなイメージがあるのに対し、こちらはただひらがなを変換するだけの機能に絞っているので謙虚にKKCにしました。

[^1]: 工藤拓. 2018. 形態素解析の理論と実装. pp. 35