MeCab のユーザー辞書作成のためのコスト計算

# はじめに
　書籍「Rによるテキストマイニング　tidytextを活用したデータ分析と可視化の基礎」のサイトにある[「付録1　RMeCabを用いた日本語テキストマイニング」](https://www.oreilly.co.jp/pub/9784873118307/appa.html)を参考に、新美南吉作「ごん狐」のワードクラウドづくりに取り組んだが、書かれている通り「ごん」「兵十」が現れない。

　そこで、「ごん」「兵十」が現れるワードクラウドが作りたくて、[MeCabの作者のサイト](https://taku910.github.io/mecab/)を参考に、Google Colaboratory で、MeCabのユーザー辞書の作成に取り組んでみた。

# 「コストの自動推定機能」によるユーザー辞書作成
## 準備

　ます、ColabでMeCabが使えるようにする。[「Google ColabにMeCabとipadic-NEologdをインストールする」](https://qiita.com/jun40vn/items/78e33e29dce3d50c2df1)を参考にした。

```python
! apt-get install -y mecab libmecab-dev mecab-ipadic-utf8 > /dev/null 2>&1
! pip install mecab-python3 > /dev/null 2>&1
! ln -s /etc/mecabrc /usr/local/etc/mecabrc
```
　
　次に、MeCabの作者のサイトにある[「単語の追加方法」](https://taku910.github.io/mecab/dic.html)に従い、次の順で、準備を行った。

### １．modelファイルのダウンロード

```python
import urllib.request
url = 'https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7bnc5aFZSTE9qNnM'
file_name = 'mecab-ipadic-2.7.0-20070801.model'
save_name = file_name + '.bz2'
urllib.request.urlretrieve(url, save_name)
```

### ２．modelファイルの解凍

```python
import bz2, shutil
file_name = 'mecab-ipadic-2.7.0-20070801.model'
save_name = file_name + '.bz2'
with bz2.BZ2File(save_name, "rb") as fr:
  with open(file_name,"wb") as fw:
    shutil.copyfileobj(fr,fw)
```

### ３．modelファイルの文字コードをutf-8へ変換

```python
import codecs
file_name = 'mecab-ipadic-2.7.0-20070801.model'
with codecs.open(file_name, 'r', encoding='euc_jp') as f_in:
  with codecs.open(file_name + '.utf8', 'w', encoding='utf_8') as f_out:
    f_out.write(f_in.read())
```

### ４．utf-8へ変換したmodelファイルの6行目を「charset: utf-8」に書き換え

```python
! sed -i -e "s!charset: euc-jp!charset: utf-8!g" mecab-ipadic-2.7.0-20070801.model.utf8
```

### ５．システム辞書のcsv、defファイルの文字コードをutf-8へ変換、コピー

```python
import os, codecs
dicDir_in = '/usr/share/mecab/dic/ipadic'
dicDir_out = '/var/lib/mecab/dic/debian'
for file in os.listdir(dicDir_in):
  if file.endswith('.csv') or file.endswith('.def'):
    with codecs.open(dicDir_in + '/' + file, 'r', encoding='euc_jp') as f_in:
      with codecs.open(dicDir_out + '/'+ file, 'w', encoding='utf_8') as f_out:
        f_out.write(f_in.read())
```

　5.は、`/etc/mecabrc`で、システム辞書のフォルダが`/var/lib/mecab/dic/debian`になっていたので、ここをユーザー辞書作成のシステム辞書フォルダにしていたが、csv、defファイルがなかったので、文字コードをutf-8に変換するついでにコピーした。
　ユーザー辞書作成には、csv、defファイルが必要なことになかなか気づくことができず苦労した。

　最初は、文字コードはeuc-jpのままで実行していたが、エラーでユーザー辞書ができなかった。必ず文字コードはutf-8に変更してください。これにもなかなか気づくことができず苦労した。

## modelファイルによるユーザー辞書の作成

　今回は、品詞は、すべて「名詞、固有名詞、一般、＊」に統一した。また、「原形、読み、発音」はすべて「＊」にしている。

```python
import csv
 
# ユーザ辞書へ追加したい名詞のList
target_txt = ['ごん', '兵十', '加助', '弥助', 'おはぐろ', '新兵衛']

# user_dic.csv の作成
with open('user_dic.csv', "w") as f:
  writer = csv.writer(f)
  for i in range(len(target_txt)):
    dic = [target_txt[i]] + [''] * 3 + ['名詞','固有名詞','一般'] +  ['*'] * 6
    writer.writerow(dic)

# modelファイルを利用しコスト値を自動推定したユーザー辞書の作成
! /usr/lib/mecab/mecab-dict-index \
    -m mecab-ipadic-2.7.0-20070801.model.utf8 \
    -d /var/lib/mecab/dic/debian -t utf-8 \
    -u user.dic \
    user_dic.csv -f utf-8
```

　できあがったユーザー辞書を確認してみる。

```python
import MeCab
tagger = MeCab.Tagger('-O wakati -u user.dic')
print(tagger.parse('その中山から、少しはなれた山の中に、「ごん狐」という狐がいました。'))
print(tagger.parse('「兵十だな」と、ごんは思いました。'))
```

　結果は次のようになった。１行目の「ごん」は成功しているが、２行目の「兵十」と「ごん」は失敗している。

```
その 中山 から 、 少し は なれ た 山 の 中 に 、 「 ごん 狐 」 という 狐 が い まし た 。 

「 兵 十 だ な 」 と 、 ご ん は 思い まし た 。 
```

# 最適なコストを求める

　modelファイルを使うやり方では、うまくいかなかったので、[「あらびき日記　MeCab の形態素解析誤りを修正する生起コストの求め方」](https://abicky.net/2016/11/28/204542/)とMeCabの作者のサイトにある[「スクリプト言語のバインディング」](https://taku910.github.io/mecab/bindings.html)を参考に、最適なコストを求めユーザー辞書を作成するコードを書いてみた。

```python
import MeCab
import csv


def make_dic(text):
    dic = [text, 1288, 1288, 20000, '名詞', '固有名詞', '一般'] + ['*'] * 6

    for h in range(len(h_txt)):
      for i in range(len(t_txt)):
        txt = [''] * 2
        txt[0] = h_txt[h] + text + t_txt[i]
        if h_txt[h] == '':
          txt[1] = text
        else:
          txt[1] = h_txt[h] + '\t*\n' + text
        if t_txt[i] == '':
          txt[1] = txt[1] + '\t名詞,固有名詞,一般,*\nEOS\n'
        else:
          txt[1] = txt[1] + '\t名詞,固有名詞,一般,*\n' + t_txt[i] + '\t*\nEOS\n'

        cst = [0] * 2
        for j in range(2):
          node = tagger[j].parseToNode(txt[j])
          while node.stat != 3:
            if node.surface == text:
              wcst = node.wcost
            node = node.next
          cst[j] = node.cost
        wcst = wcst - ( cst[1] -cst[0] ) - 1
 
        if dic[3] > wcst:
          dic[3] = wcst
    return dic


# ユーザ辞書へ追加したい名詞のリスト
target_txt = ['ごん', '兵十', '加助', '弥助', 'おはぐろ', '新兵衛']

# コスト計算のため、単語の前後につける語のリスト
h_txt = ['そして', '日']
t_txt = ['です', '、']

tagger = [''] * 2
tagger[0] = MeCab.Tagger()
tagger[1] = MeCab.Tagger('-p')

# user_dic.csv の作成
with open('user_dic.csv', "w") as f:
  writer = csv.writer(f)
  for k in range(len(target_txt)):
    dicLine = make_dic(target_txt[k])
    writer.writerow(dicLine)

# ユーザ辞書のコンパイル
! /usr/lib/mecab/mecab-dict-index \
    -d /var/lib/mecab/dic/debian -t utf-8 \
    -u user.dic \
    user_dic.csv-f utf-8
```

 ユーザー辞書を確認してみるとうまくいった。

```
その 中山 から 、 少し は なれ た 山 の 中 に 、 「 ごん 狐 」 という 狐 が い まし た 。 

「 兵十 だ な 」 と 、 ごん は 思い まし た 。 
```

　しかし、まだ「こないだうなぎをぬすみやがったあのごん狐めが、またいたずらをしに来たな。」を分かち書きすると、次のようになる。

```
こないだ う な ぎをぬすみやがったあのごん 狐 め が 、 また いたずら を し に 来 た な 。
```

　これには、「ぎをぬすみやがったあのごん」のコストを21130にして、ユーザー辞書に追加するとうまくいった。


　pythonは初心者です。ググりながらコードを作成しました。間違い等をご指摘いただけたらありがたいです。

# 参考サイト

- [Rによるテキストマイニング　tidytextを活用したデータ分析と可視化の基礎
付録1　RMeCabを用いた日本語テキストマイニング]
(https://www.oreilly.co.jp/pub/9784873118307/appa.html)

- [MeCab: Yet Another Part-of-Speech and Morphological Analyzer]
(https://taku910.github.io/mecab/)

- [Google ColabにMeCabとipadic-NEologdをインストールする]
(https://qiita.com/jun40vn/items/78e33e29dce3d50c2df1)

- [英語の勉強サイト
Pythonプログラミング：bz2解凍進行状況をtqdmで視覚化]
(https://eigo.rumisunheart.com/2018/04/10/how-to-decompress-bz2-file-in-python-2/)

- [TechAcademyマガジン
PythonでCSVファイルの文字コードを変換する方法【初心者向け】]
(https://techacademy.jp/magazine/21128)

- [桃缶食べたい。
MeCab の IPA 辞書を UTF8 化する]
(https://blog.chocolapod.net/momokan/entry/54)

- [あらびき日記
MeCab の形態素解析誤りを修正する生起コストの求め方]
(https://abicky.net/2016/11/28/204542/)