4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2021-08-29

はじめに

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

参考サイト

4
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?