MeCab用辞書の .def ファイル中の左右まとめ

MeCab 用の辞書を学習するときに、.def 中の左右の概念がファイルごとにこんがらがるので実行しながらまとめ。

こんがらがる原因はここら辺を参照。
> 左文脈素性(その形態素を左側から見た時の素性), 右文脈素性(その形態素を左側から見た時の素性)の3つが使われます. 

https://taku910.github.io/mecab/learn.html#config

# 準備

リソースは、UniDic（unidic-cwj-3.1.1-full.zip）のものを再利用する。

### コーパスとトークンリスト

まず、UniDic の lex.csv から適当に２文程度のミニコーパスを作る。
1列目の表層形と以降のCSVフィールドの間にあるのはタブ１個。
[Chaki](https://ja.osdn.net/projects/chaki/)でいうところの.mecab形式。
UniDicのフィールドには１カラムに"動詞%F1,形容詞%F2@-1"みたいなカンマが入る列もあるのでガチのCSV。ちゃんとエスケープするためにダブルクォーテーションでくくってあるので、不用意にナイーブなカンマsplitはしてはいけない。
EOSの直後はすぐ改行。EOS行にはタブは入れちゃダメ。EOS\nしかダメ。
```def:mini_corpus.mecab
くるま	名詞,普通名詞,一般,*,*,*,クルマ,車,くるま,クルマ,くるま,クルマ,和,ク濁,基本形,*,*,*,*,体,クルマ,クルマ,クルマ,クルマ,0,C2,*,2895297718133248,10533
で	助詞,接続助詞,*,*,*,*,テ,て,で,デ,で,デ,和,*,*,*,*,*,*,接助,デ,デ,デ,デ,*,"動詞%F1,形容詞%F2@-1",*,6837330270888448,24874
待つ	動詞,一般,*,*,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,*,*,*,*,*,*,用,マツ,マツ,マツ,マツ,1,C1,*,9848884062986923,35830
EOS
車	名詞,普通名詞,一般,*,*,*,クルマ,車,車,クルマ,車,クルマ,和,ク濁,基本形,*,*,*,*,体,クルマ,クルマ,クルマ,クルマ,0,C2,*,2895297651024384,10533
で	助詞,接続助詞,*,*,*,*,テ,て,で,デ,で,デ,和,*,*,*,*,*,*,接助,デ,デ,デ,デ,*,"動詞%F1,形容詞%F2@-1",*,6837330270888448,24874
待つ	動詞,一般,*,*,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,*,*,*,*,*,*,用,マツ,マツ,マツ,マツ,1,C1,*,9848884062986923,35830
EOS
```

つぎに、上のmini_corpus.mecab に入ってるエントリだけの mini_lex.csv を作る。
コピペで学習済みの.csvから持ってくると、right-id, left-id, 生起costの値(2～4列目)がすでに埋まっているので0,0,0,に全置換しておく。
```csv:mini_lex.csv
くるま,0,0,0,名詞,普通名詞,一般,*,*,*,クルマ,車,くるま,クルマ,くるま,クルマ,和,ク濁,基本形,*,*,*,*,体,クルマ,クルマ,クルマ,クルマ,0,C2,*,2895297718133248,10533
車,0,0,0,名詞,普通名詞,一般,*,*,*,クルマ,車,車,クルマ,車,クルマ,和,ク濁,基本形,*,*,*,*,体,クルマ,クルマ,クルマ,クルマ,0,C2,*,2895297651024384,10533
くる,0,0,0,動詞,非自立可能,*,*,カ行変格,終止形-一般,クル,来る,くる,クル,くる,クル,和,*,*,*,*,*,*,用,クル,クル,クル,クル,1,C1,*,2891174448865963,10518
まで,0,0,0,助詞,副助詞,*,*,*,*,マデ,まで,まで,マデ,まで,マデ,和,*,*,*,*,*,*,副助,マデ,マデ,マデ,マデ,*,"名詞%F2@1,形容詞%F2@1,動詞%F2@1",*,9865651581755904,35891
で,0,0,0,助詞,接続助詞,*,*,*,*,テ,て,で,デ,で,デ,和,*,*,*,*,*,*,接助,デ,デ,デ,デ,*,"動詞%F1,形容詞%F2@-1",*,6837330270888448,24874
待つ,0,0,0,動詞,一般,*,*,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,*,*,*,*,*,*,用,マツ,マツ,マツ,マツ,1,C1,*,9848884062986923,35830
```

### .def ファイル

基本的には UniDic の .def ファイルをそのまま使用。
書き換えるのは、以下の rewrite.def, feature.def。上と同じ理由で unk.def も 0,0,0, 置換しておく。

```def:rewrite.def
# node:
# $1: pos1
# $2: pos2
# $3: pos3
# $4: pos4
# $5: cType
# $6: cForm
# $7: lForm
# $8: lemma
# $9: orth
# $10: pron
# $11: orthBase
# $12: pronBase
# $13: goshu
# $14: iType
# $15: iForm
# $16: fType
# $17: fForm
# $18: iConType
# $19: fConType
# $20: type
# $21: kana
# $22: kanaBase
# $23: form
# $24: formBase
# $25: aType
# $26: aConType
# $27: aModType
# unk:
# $1: pos1
# $2: pos2
# $3: pos3
# $4: pos4
# $5: cType
# $6: cForm

[unigram rewrite]
BOS/EOS,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*	$1,*,*,*,*,*,*,BOS/EOS,BOS/EOS,BOS/EOS,*,*,BOS/EOS,*,*,*
*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*	$1,$2,$3,$4,$5,$6,$7,$8,$9,$11,$10,$12,$13,$25,$26,$27
*,*,*,*,*,*	$1,$2,$3,$4,$5,$6,*,*,*,*,*,*,*

[left rewrite]
BOS/EOS,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*	X$1,*,*,*,*,*,XBOS/EOS,XBOS/EOS,XBOS/EOS,*,*,*,*,*,*
*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*	X$1,X$2,X$3,X$4,X$5,X$6,X$9,X$8,X$13,X$16,X$17,X$18,X$25,X$26,X$27
*,*,*,*,*,*	OX$1,$2,$3,$4,$5,$6,*,*,*,*,*,*

[right rewrite]
BOS/EOS,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*	Y$1,*,*,*,*,*,YBOS/EOS,YBOS/EOS,YBOS/EOS,*,*,*,*,*,*
*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*	Y$1,Y$2,Y$3,Y$4,Y$5,Y$6,*,Y$8,Y$13,Y$14,Y$15,Y$19,Y$25,Y$26,Y$27
*,*,*,*,*,*	OY$1,$2,$3,$4,$5,$6,*,*,*,*,*,*
```
語彙化のrewrite行は消して、
left rewrite したら素性値の頭にXが付いて、right rewrite したら素性値の頭にYが付くように書き換え。
元のファイルでは書字形等はアスタリスク「*」につぶされる設定だったのを
```
,X$9,X$8,
```
```
,Y*,Y$8,
```
であえて語彙化しつつ左右非対称になる設定に修正。
EOS/BOS 行が dicrc と長さ違ったので同じになるよう調整。
未知語の rewrite の場合はXYの前に O がつくようにしている。

```def:feature.def
# [0]: pos1
# [1]: pos2
# [2]: pos3
# [3]: pos4
# [4]: cType
# [5]: cForm
# [6]: lForm
# [7]: lemma
# [8]: orth
# [9]: orthBase
# [10]: pron
# [11]: pronBase
# [12]: goshu

UNIGRAM G01:%F[0]

UNIGRAM C01:%F?[4]
UNIGRAM C03:%F?[4],%F?[5]

UNIGRAM O01:%F?[8]
UNIGRAM O02:%F?[9]

UNIGRAM P01:%F?[10]
UNIGRAM P02:%F?[11]

UNIGRAM W01:%F?[12]

UNIGRAM T01:%t

BIGRAM G_G01:%L[0]/%R[0]

BIGRAM O_O01:%L?[6]/%R?[6]
BIGRAM O_O02:%L?[6]/%R?[7]
BIGRAM O_O03:%L?[7]/%R?[7]
```
素性テンプレートはこんな感じに簡素化。
BIGRAM素性は、L/Rのカタチになっている。

これで準備完了。

# 学習実行

```
> mecab-dict-index
> mecab-cost-train -c 1.0 mini_corpus.mecab model
```

# 学習実行結果

```def:model
eta: 5e-05
freq: 1
C: 1
eval-size: 10
unk-eval-size: 4
charset: UTF-8

-0.0742225309004440	C01:カ行変格
-0.0000000000000000	C01:五段-タ行
-0.0742225309004440	C03:カ行変格,終止形-一般
-0.0000000000000000	C03:五段-タ行,終止形-一般
0.0000000000000000	G01:BOS/EOS
-0.0000000000000000	G01:助詞
-0.0742225309004440	G01:動詞
0.0742225309004438	G01:名詞
-0.0742225309004440	G_G01:YBOS/EOS/X動詞
0.0742225309004438	G_G01:YBOS/EOS/X名詞
-0.0000000000000000	G_G01:Y助詞/X動詞
0.0000000000000000	G_G01:Y動詞/XBOS/EOS
-0.0742225309004440	G_G01:Y動詞/X助詞
0.0742225309004440	G_G01:Y名詞/X助詞
-0.0742225309004440	O01:くる
0.0742225309004438	O01:くるま
0.0742225309004440	O01:で
-0.0742225309004440	O01:まで
-0.0000000000000000	O01:待つ
0.0000000000000000	O01:車
-0.0742225309004440	O02:くる
0.0742225309004438	O02:くるま
0.0742225309004440	O02:で
-0.0742225309004440	O02:まで
-0.0000000000000000	O02:待つ
0.0000000000000000	O02:車
-0.0742225309004440	O_O01:YBOS/EOS/Xくる
0.0742225309004438	O_O01:YBOS/EOS/Xくるま
0.0000000000000000	O_O01:YBOS/EOS/X車
-0.0742225309004440	O_O02:YBOS/EOS/X来る
0.0742225309004438	O_O02:YBOS/EOS/X車
-0.0742225309004440	O_O03:YBOS/EOS/X来る
0.0742225309004438	O_O03:YBOS/EOS/X車
0.0742225309004440	O_O03:Yて/X待つ
-0.0742225309004440	O_O03:Yまで/X待つ
0.0000000000000000	O_O03:Y待つ/XBOS/EOS
-0.0742225309004440	O_O03:Y来る/Xまで
0.0742225309004440	O_O03:Y車/Xて
-0.0742225309004440	P01:クル
0.0742225309004438	P01:クルマ
0.0742225309004440	P01:デ
-0.0000000000000000	P01:マツ
-0.0742225309004440	P01:マデ
-0.0742225309004440	P02:クル
0.0742225309004438	P02:クルマ
0.0742225309004440	P02:デ
-0.0000000000000000	P02:マツ
-0.0742225309004440	P02:マデ
0.0000000000000000	T01:0
0.0000000000000000	T01:2
-0.0000000000000002	T01:6
0.0000000000000000	W01:和
```

BIGRAM 素性を見たらわかるけれど、
- L[]にYが入っているので　rewrite.def の [right rewrite] が feature.def の L に対応
- R[]にXが入っているので　rewrite.def の [left rewrite] が feature.def の R に対応
- ```O_O03:Y来る/Xまで``` という素性ができているので、feature.def の L はトークン連接の左トークンに対応、Rは右トークンに対応。ここは直感的。

図にまとめるとこんな感じ。
<img width="600px" alt="conj1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361891/32bd5830-9643-65d9-ee4d-2e6cc457258d.png">

# matrix 作成

```
> mecab-dict-gen -o ../final -m model
```

```def:matrix.def
15 16
1 1 0
1 2 0
1 3 0
1 4 0
1 5 0
1 6 0
1 7 0
1 8 0
1 9 0
1 0 0
1 10 0
1 11 0
1 12 0
1 13 0
1 14 0
1 15 0
2 1 0
(略)
0 1 0
0 2 0
0 3 0
0 4 0
0 5 0
0 6 0
0 7 0
0 8 0
0 9 0
0 0 0
（略）
14 12 0
14 13 0
14 14 0
14 15 0
```
id 0 がファイルの頭でなくて途中にいるせいでわかりづらいけれど、1行目に書いてある通り 15x16 サイズの matrix が完成している。
左右非対称のサイズになっているのは、rewrite.def でそうなるように設定したから。

```def:right-id.def
1 OY名詞,固有名詞,一般,*,*,*,*,*,*,*,*,*
2 OY名詞,固有名詞,人名,一般,*,*,*,*,*,*,*,*
3 OY名詞,固有名詞,地名,一般,*,*,*,*,*,*,*,*
4 OY名詞,数詞,*,*,*,*,*,*,*,*,*,*
5 OY名詞,普通名詞,サ変可能,*,*,*,*,*,*,*,*,*
6 OY名詞,普通名詞,一般,*,*,*,*,*,*,*,*,*
7 OY感動詞,一般,*,*,*,*,*,*,*,*,*,*
8 OY空白,*,*,*,*,*,*,*,*,*,*,*
9 OY補助記号,一般,*,*,*,*,*,*,*,*,*,*
0 YBOS/EOS,*,*,*,*,*,YBOS/EOS,YBOS/EOS,YBOS/EOS,*,*,*,*,*,*
10 Y助詞,Y副助詞,Y*,Y*,Y*,Y*,*,Yまで,Y和,Y*,Y*,Y*,Y*,"Y名詞%F2@1,形容詞%F2@1,動詞%F2@1",Y*
11 Y助詞,Y接続助詞,Y*,Y*,Y*,Y*,*,Yて,Y和,Y*,Y*,Y*,Y*,"Y動詞%F1,形容詞%F2@-1",Y*
12 Y動詞,Y一般,Y*,Y*,Y五段-タ行,Y終止形-一般,*,Y待つ,Y和,Y*,Y*,Y*,Y1,YC1,Y*
13 Y動詞,Y非自立可能,Y*,Y*,Yカ行変格,Y終止形-一般,*,Y来る,Y和,Y*,Y*,Y*,Y1,YC1,Y*
14 Y名詞,Y普通名詞,Y一般,Y*,Y*,Y*,*,Y車,Y和,Yク濁,Y基本形,Y*,Y0,YC2,Y*
```

```def:left-id.def
1 OX名詞,固有名詞,一般,*,*,*,*,*,*,*,*,*
2 OX名詞,固有名詞,人名,一般,*,*,*,*,*,*,*,*
3 OX名詞,固有名詞,地名,一般,*,*,*,*,*,*,*,*
4 OX名詞,数詞,*,*,*,*,*,*,*,*,*,*
5 OX名詞,普通名詞,サ変可能,*,*,*,*,*,*,*,*,*
6 OX名詞,普通名詞,一般,*,*,*,*,*,*,*,*,*
7 OX感動詞,一般,*,*,*,*,*,*,*,*,*,*
8 OX空白,*,*,*,*,*,*,*,*,*,*,*
9 OX補助記号,一般,*,*,*,*,*,*,*,*,*,*
0 XBOS/EOS,*,*,*,*,*,XBOS/EOS,XBOS/EOS,XBOS/EOS,*,*,*,*,*,*
10 X助詞,X副助詞,X*,X*,X*,X*,Xまで,Xまで,X和,X*,X*,X*,X*,"X名詞%F2@1,形容詞%F2@1,動詞%F2@1",X*
11 X助詞,X接続助詞,X*,X*,X*,X*,Xで,Xて,X和,X*,X*,X*,X*,"X動詞%F1,形容詞%F2@-1",X*
12 X動詞,X一般,X*,X*,X五段-タ行,X終止形-一般,X待つ,X待つ,X和,X*,X*,X*,X1,XC1,X*
13 X動詞,X非自立可能,X*,X*,Xカ行変格,X終止形-一般,Xくる,X来る,X和,X*,X*,X*,X1,XC1,X*
14 X名詞,X普通名詞,X一般,X*,X*,X*,Xくるま,X車,X和,X*,X*,X*,X0,XC2,X*
15 X名詞,X普通名詞,X一般,X*,X*,X*,X車,X車,X和,X*,X*,X*,X0,XC2,X*
```

matrix.def の最終行が ```14 15 0``` なので、*-id.def の最終行と見比べて、
matrix.def の 1列目が right-id, 2列目が left-id に対応。

また right-id.def に Y に rewrite された素性、left-idに X にrewrite された素性が入っているので、
- right-id.def が feature.def の L 、rewrite.def の [right rewrite] に対応
- left-id.def が feature.def の R 、rewrite.def の [left rewrite] に対応

```csv:mini_lex.csv
くるま,14,14,-259,名詞,普通名詞,一般,*,*,*,クルマ,車,くるま,クルマ,くるま,クルマ,和,ク濁,基本形,*,*,*,*,体,クルマ,クルマ,クルマ,クルマ,0,C2,*,2895297718133248,10533
車,15,14,-155,名詞,普通名詞,一般,*,*,*,クルマ,車,車,クルマ,車,クルマ,和,ク濁,基本形,*,*,*,*,体,クルマ,クルマ,クルマ,クルマ,0,C2,*,2895297651024384,10533
くる,13,13,363,動詞,非自立可能,*,*,カ行変格,終止形-一般,クル,来る,くる,クル,くる,クル,和,*,*,*,*,*,*,用,クル,クル,クル,クル,1,C1,*,2891174448865963,10518
まで,10,10,207,助詞,副助詞,*,*,*,*,マデ,まで,まで,マデ,まで,マデ,和,*,*,*,*,*,*,副助,マデ,マデ,マデ,マデ,*,"名詞%F2@1,形容詞%F2@1,動詞%F2@1",*,9865651581755904,35891
で,11,11,-207,助詞,接続助詞,*,*,*,*,テ,て,で,デ,で,デ,和,*,*,*,*,*,*,接助,デ,デ,デ,デ,*,"動詞%F1,形容詞%F2@-1",*,6837330270888448,24874
待つ,12,12,51,動詞,一般,*,*,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,*,*,*,*,*,*,用,マツ,マツ,マツ,マツ,1,C1,*,9848884062986923,35830
```

これは学習後、0,0,0 に id と生起コストが振り直された mini_lex.csv 。
> 車,15,14,-155,名詞,普通名詞,一般,*,*,*,クルマ,車,車,クルマ

というのがいるので、*-id.def の最終行と見比べて、
.csv の 2列目が left-id, 3列目が right-id に対応。
matrix.def と逆なので注意。

図にまとめるとこう。

<img width="400px" alt="matrix.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361891/6df6a47f-8d49-de86-bd75-6acdca1ba3bc.png"><br>
<img width="400px" alt="csv.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361891/5773e7ec-1b67-f40b-c737-09f0a31f3157.png">

さらにこう。

<img width="600px" alt="conj2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361891/35297d33-295f-8ced-04ef-0b4c004a190a.png">

ややこしいったらない。

今回使用したファイル、[ここ](https://github.com/TeruakiOka/mecab-mini-check)に置きました。


# 追記
今回、matrix.def と left- right-id.def が0始まりでないのは、dicrcで定義したBOS/EOS素性列が、rewrite.def の書き換えルールにマッチしていないからです。