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


はじめに

 書籍「Rによるテキストマイニング tidytextを活用したデータ分析と可視化の基礎」のサイトにある「付録1 RMeCabを用いた日本語テキストマイニング」を参考に、新美南吉作「ごん狐」のワードクラウドづくりに取り組んだが、書かれている通り「ごん」「兵十」が現れない。

 そこで、「ごん」「兵十」が現れるワードクラウドが作りたくて、MeCabの作者のサイトを参考に、Google Colaboratory で、MeCabのユーザー辞書の作成に取り組んでみた。

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

準備

 ます、ColabでMeCabが使えるようにする。「Google ColabにMeCabとipadic-NEologdをインストールする」を参考にした。

! 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の作者のサイトにある「単語の追加方法」に従い、次の順で、準備を行った。

1.modelファイルのダウンロード

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)

2.modelファイルの解凍

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)

3.modelファイルの文字コードをutf-8へ変換

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())

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

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

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

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ファイルによるユーザー辞書の作成

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

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

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

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

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

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

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

最適なコストを求める

 modelファイルを使うやり方では、うまくいかなかったので、「あらびき日記 MeCab の形態素解析誤りを修正する生起コストの求め方」とMeCabの作者のサイトにある「スクリプト言語のバインディング」を参考に、最適なコストを求めユーザー辞書を作成するコードを書いてみた。

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は初心者です。ググりながらコードを作成しました。間違い等をご指摘いただけたらありがたいです。

参考サイト