芋の独り言

当ブログへのアクセスは当ブログのプライバシーポリシーに同意したものとみなします.

Ubuntuに言語処理関連ツールをインストールする方法まとめ③

MeCab以外からneologd辞書を使えるようにする”のが今回のテーマ.
とはいえ,mecab辞書と形式が違うために,除外しなければならないワードもあり,neologd辞書をそのまま使えるように したわけではありません.その点を注意していただきたいと思います.
また,”ユーザ名”やパスは各々の環境に合わせて適宜変更してください.
あと,コードブロックが見づらいかもしれません...よい書き方知っている方がいれば教えてください!

事前にやっておくべきこと

mecab辞書の形式

ipadic-neologd辞書は

表層形,左文脈ID,右文脈ID,コスト,品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用型,活用形,原形,読み,発音

といった形式で,これを考慮して,各形態素解析器の辞書の形式に変換する必要があります.

やっていなっかたら,やっておくべき注意点

juman++には推奨ライブラリがあり,これらをインストールした後にインストールしたjuman++でないと,辞書のインストール自体は成功しても,jumanppコマンドが使えず,juman++での形態素解析ができなくなります.
なので,ユーザ辞書の追加には,推奨ライブラリは事前に入れておくべき必須ツールです.少なくとも,私の環境かでは,インストールし直したことで,改善できました.
ちなみに,推奨ライブラリは以下の3つです.いずれも最新版のインストールでよいかと思います.

  1. libunwind
  2. gperftools
  3. Boost

以上のライブラリの導入は以下の過去記事に書きましたので,参照してください. 推奨ライブラリを入れずにjuman++をインストールした場合,推奨ライブラリをインストールしてから再度同じステップでjuman++をインストールしましょう.

kusoimox.hatenablog.jp

この工程をやらないと,辞書登録後のjumanppコマンドで

terminate called after throwing an instance of 'std::out_of_range'
  what():  _Map_base::at

もしくはSegmantation Faultと表示されて,解析できないので気を付けましょう.

新たにインストールするモジュール

$ pip install mojimoji
$ pip install jaconv
$ sudo apt-get install zsh

というように,必要なモジュールは用意・アップデートしておきましょう. ”jaconv”は正規化処理などに使うモジュールで,日本語処理において必須と言えそうなツールのようなので,この際に入れておいた方がよいかもしれませんね.

また,/dict-build/userdic内にあるdummy.dicは削除しておきましょう.0バイトのファイルなんで,特に置いておく必要はないと思います.

neologd2jumanを使う場合の注意

本記事のように自分でスクリプトとフォルダを作るのではなく,すでに公開されているモジュール”neologd2juman”を使う場合に関して, まず,インストールして,モジュールを使う方法は

$ git clone https://github.com/fumankaitori/neologd2juman.git
$ cd neologd2juman
$ sudo make

です.注意点として,デフォルトのPythonの環境が3.7以降の場合はneologd2juman.pyでエラーが出ると思いますので,

def my_csv_reader(csv_reader):
    """
    NULL回避のためのcsvジェネレータ
    :return:
    """ 
    while True:
        try:
            yield next(csv_reader)
        except csv.Error:
            pass
        except StopIteration:
            return

というように'StopIteration'を追加したほうがよいです.

スクリプト

以下のスクリプトをまとめた”neologd2jumanpp_and_kytea”フォルダ(フォルダ名は各々好きなものにしてかまいません)を端末から開きsudo makeを実行すれば,Neologd辞書のダウウンロードから,mecabへのインストール,kyteaの辞書作り+辞書学習,juman++用の辞書作成と ファルダへの移動まで一括して行います.この後に,juman++への辞書登録をやりましょう.

Makefile

install:
  wget --no-check-certificate https://github.com/neologd/mecab-ipadic-neologd/tarball/master -O mecab-ipadic-neologd.tar
  tar -xvf mecab-ipadic-neologd.tar
  rm -rf /home/ユーザ名/neologd-mecab-ipadic-neologd-*
  mv neologd-mecab-ipadic-neologd-* /home/hiro/
  wget --no-check-certificate https://github.com/neologd/mecab-unidic-neologd/tarball/master -O mecab-unidic-neologd.tar
  tar -xvf mecab-unidic-neologd.tar
  rm -rf /home/ユーザ名/neologd-mecab-unidic-neologd-*
  mv neologd-mecab-unidic-neologd-*  /home/ユーザ名/
  # mecabにneologd辞書をインストール
  sudo /home/ユーザ名/neologd-mecab-ipadic-neologd-*/bin/install-mecab-ipadic-neologd -n -a -y
  sudo /home/ユーザ名/neologd-mecab-unidic-neologd-*/bin/install-mecab-unidic-neologd -n -y
  # csvファイルに変換  
  sudo xz -dc /home/ユーザ名/neologd-mecab-ipadic-neologd-*/seed/mecab-user-dict-seed.*.csv.xz > mecab-ipadic-user-dict-seed.csv
  sudo xz -dc /home/ユーザ名/neologd-mecab-unidic-neologd-*/seed/mecab-unidic-user-dict-seed.*.csv.xz > mecab-unidic-user-dict-seed.csv
  # kytea用に辞書作成し、学習させる
  /home/ユーザ名/anaconda3/bin/python kytea_make_unidic_dict.py mecab-unidic-user-dict-seed.csv kytea-unidic-user-dict.txt
  train-kytea -full train.txt -dict kytea-unidic-user-dict.txt -model train.model
  # jumanpp用に辞書作成し、辞書をインストール
  /home/ユーザ名/anaconda3/bin/python ipadic_neologd2juman.py mecab-ipadic-user-dict-seed.csv jumanpp-ipadic-neologd-dict
  rm -rf /home/ユーザ名/jumanpp-1.02/dict-build/userdic/jumanpp-ipadic-neologd-dict-*.dic
  sudo chmod a=rwx jumanpp-ipadic-neologd-dict-*.dic
  mv jumanpp-ipadic-neologd-dict-*.dic /home/ユーザ名/jumanpp-1.02/dict-build/userdic/

/home/ユーザ名/anaconda3/bin/python という風にしないと,Ubuntuに元々入っているPythonスクリプトを実行しようとしてエラーになります.pipで入れたモジュールがAnaconda内にあるため,モジュール使用できずに起こるエラーだと思われます.
なので,インストールしたAnacondaの中のPythonを指定し,それでスクリプトを実行してもらうように,以上のような/home/ユーザ名/anaconda3/bin/pythonとします.標準ライブラリだけでできてるスクリプトならこのような変更はいらないんですけど,pipcondaでインストールしたモジュールを使うスクリプトをMakeファイルとかで呼び出して使う場合はこのような変更が必要です.
他にいい方法があったら教えてください~

ipadic_neologd2juman.py:ipadic-neologd辞書のcsvファイルをjuman形式にした辞書の作成するスクリプト

#-*- coding:utf-8 -*-

import sys
import jaconv


def System_Message(i):

    if i != 0 and i % 100000 == 0:
        sys.stderr.write("{}M lines done\n".format(i / 1000000))
    elif i != 0 and i % 10000 == 0:
        sys.stderr.write(".")
        sys.stderr.flush()



dic = sys.argv[1]
file_name = sys.argv[2]

with open(dic,mode='r',encoding='utf-8') as d:

    for i,line in enumerate(d):

        if 'カッコカッコ' in line:
            continue

        if 'カオモジ' in line:
            kaomoji = True
        else:
            kaomoji = False

        line = line.split(',')

        if line[4] == '記号':
            if kaomoji:
                with open(file_name+'-kaomoji.dic',mode='a',encoding="utf-8") as f:
                    f.write('(特殊 (記号 ((読み {0})(見出し語 {1})(意味情報 "顔文字"))))\n'.format(line[0],line[-3]))
            else:
                with open(file_name+'-emoji.dic',mode='a',encoding="utf-8") as f:
                    f.write('(特殊 (記号 ((読み {0})(見出し語 {1})(意味情報 "代表表記:{2}/* 絵文字"))))\n'.format(jaconv.kata2hira(jaconv.h2z(line[-2])),line[0],line[-3]))

            System_Message(i)
            continue

        # 排除対象
        if ' ' in line[0]:
            continue
        if '(' in line[0]:
            continue
        if ')' in line[0]:
            continue


        if line[4] == "名詞":
            if line[5] == "固有名詞":
                if line[6] == "人名":
                    with open(file_name+'-noun.dic',mode='a',encoding="utf-8") as f:
                        f.write('(名詞 (人名 ((読み {0})(見出し語 {1})(意味情報 "人名"))))\n'.format(jaconv.kata2hira(jaconv.h2z(line[-2])),line[0]))
                if line[6] == "地域":
                    with open(file_name+'-noun.dic',mode='a',encoding="utf-8") as f:
                        f.write('(名詞 (地名 ((読み {0})(見出し語 {1})(意味情報 "代表表記:{2}/{3} 地名"))))\n'.format(jaconv.kata2hira(jaconv.h2z(line[-2])),line[0],line[-3],jaconv.kata2hira(jaconv.h2z(line[-2]))))
                if line[6] == "組織":
                    with open(file_name+'-noun.dic',mode='a',encoding="utf-8") as f:
                        f.write('(名詞 (組織名 ((読み {0})(見出し語 {1})(意味情報 "代表表記:{2}/{3}"))))\n'.format(jaconv.kata2hira(jaconv.h2z(line[-2])),line[0],line[-3],jaconv.kata2hira(jaconv.h2z(line[-2]))))
                else:
                    with open(file_name+'-noun.dic',mode='a',encoding="utf-8") as f:
                        f.write('(名詞 (固有名詞 ((見出し語 {0}) (読み {1}) (意味情報 "代表表記:{2}/{3}"))))\n'.format(line[0],jaconv.kata2hira(jaconv.h2z(line[-2])),line[-3],jaconv.kata2hira(jaconv.h2z(line[-2]))))    

                System_Message(i)
                continue
            else: # 一般名詞
                if line[5] == "一般":
                    with open(file_name+'-noun.dic',mode='a',encoding="utf-8") as f:
                        f.write('(名詞 (普通名詞 ((読み {0})(見出し語 {1})(意味情報 "代表表記:{2}/{3}"))))\n'.format(jaconv.kata2hira(jaconv.h2z(line[-2])),line[0],line[-3],jaconv.kata2hira(jaconv.h2z(line[-2]))))
                elif line[5] == "サ変接続": 
                    with open(file_name+'-noun.dic',mode='a',encoding="utf-8") as f:
                        f.write('(名詞 (サ変名詞 ((読み {0})(見出し語 {1})(意味情報 "代表表記:{2}/{3}"))))\n'.format(jaconv.kata2hira(jaconv.h2z(line[-2])),line[0],line[-3],jaconv.kata2hira(jaconv.h2z(line[-2]))))


        if line[4] == "副詞":
            with open(file_name+'-fukushi.dic',mode='a',encoding="utf-8") as f:
                f.write('(副詞 ((読み {0})(見出し語 {1})(意味情報 "代表表記:{2}/{3} 副詞識別")))\n'.format(jaconv.kata2hira(jaconv.h2z(line[-2])),line[0],line[-3],jaconv.kata2hira(jaconv.h2z(line[-2]))))


        if line[4] == "形容詞":
            with open(file_name+'-keiyoshi.dic',mode='a',encoding="utf-8") as f:
                f.write('(形容詞 ((読み {0})(見出し語 {1})(意味情報 "代表表記:{2}/{3}")))\n'.format(jaconv.kata2hira(jaconv.h2z(line[-2])),line[0],line[-3],jaconv.kata2hira(jaconv.h2z(line[-2]))))

    sys.stderr.write("{} lines done\n".format(i))

ファイル名は”ipadic_neologd2juman.py”としておくか,違うファイル名にする場合はMakefile内の該当箇所を変更しておいてください.

kytea_make_unidic_dict.py:ipadic-neologd辞書のcsvファイルをjuman形式にした辞書の作成するスクリプト

kytea_make_unidic_dict.pyは,コマンドライン引数を使ったPythonスクリプトになります.コマンドライン引数について,以下を参考にしました.何故”ipadic”辞書はkytea用に作らないかと申しますと,作ってtrain-kyteaをやったのですが,エラーがどうしても出ちゃうんですよ.なのでipadic辞書の方はkyteaに学習させません.おそらく,kyteaはipadic形式が使えないのかもしれません.

#-*- coding:utf-8 -*-
import sys

dic = sys.argv[1]
file_name = sys.argv[2]

with open(file_name,mode='w',encoding="utf-8") as f:
    with open(dic,mode='r',encoding='utf-8') as d:
        for i,line in enumerate(d):

            line = line.split(',')
            if line[4] == '記号':
                continue
            elif line[5] == '固有名詞':
                pos = line[5]
            else:    
                pos = line[4]
            f.write(line[0] + '/' + pos + '/' + line[10])
            # System Message
            if i != 0 and i % 100000 == 0:
                sys.stderr.write("{}M lines done\n".format(i / 1000000))
            elif i != 0 and i % 10000 == 0:
                sys.stderr.write(".")
                sys.stderr.flush()

        sys.stderr.write("{} lines done\n".format(i))

ファイル名は”kytea_make_unidic_dict.py”としておくか,違うファイル名にする場合はMakefile内の該当箇所を変更しておいてください.

train.txt:kytea用のコーパスデータ

コーパス/名詞/こーぱす
の/助詞/の
文/名詞/ぶん
で/助動詞/で
す/語尾/す
。/補助記号/。
もう/副詞/もう
ひと/名詞/ひと
つ/接尾辞/つ
の/助詞/の
文/名詞/ぶん
で/補助記号/で
す/語尾/す
。/補助記号/。

のようなテキストデータを作ります. ファイル名は”train.txt”としておくか,違うファイル名にする場合はMakefile内の該当箇所を変更しておいてください.

juman++への辞書登録

以上のスクリプトをまとめたフォルダ内でsudo make実行後,”/home/ユーザ名/jumanpp-1.02/dict-build”へ移動して,そこで

sudo make
sudo ./install.sh

というコマンドを実行します.sudo makeで軽く一時間かかるかと思います.以上でそのまんまではないですが,neologd辞書を mecab以外から使えるようになりました.

試用

juman++

野獣先輩が走る。
野獣先輩 やじゅうせんぱい 野獣先輩 名詞 6 固有名詞 3 * 0 * 0 "代表表記:野獣先輩/やじゅうせんぱい"
が が が 助詞 9 格助詞 1 * 0 * 0 NIL
走る はしる 走る 動詞 2 * 0 子音動詞ラ行 10 基本形 2 "代表表記:走る/はしる"
。 。 。 特殊 1 句点 1 * 0 * 0 NIL
EOS
!!( ; ロ)゚ ゚
!! !! !! 未定義語 15 その他 1 * 0 * 0 "品詞推定:名詞"
( ( ( 未定義語 15 その他 1 * 0 * 0 "品詞推定:名詞"
\  \  \  特殊 1 空白 6 * 0 * 0 "代表表記: / "
;\  ;\  ;\  未定義語 15 その他 1 * 0 * 0 "品詞推定:名詞"
ロ ロ ロ 未定義語 15 その他 1 * 0 * 0 "品詞推定:名詞"
) ) ) 未定義語 15 その他 1 * 0 * 0 "品詞推定:名詞"
゚ ; ゚ 特殊 1 記号 5 * 0 * 0 "顔文字"
@ ゚ ゚ ゚ 特殊 1 記号 5 * 0 * 0 "顔文字"
@ ゚ Д ゚ 特殊 1 記号 5 * 0 * 0 "顔文字"
@ ゚ !! ゚ 特殊 1 記号 5 * 0 * 0 "顔文字"
\  \  \  特殊 1 空白 6 * 0 * 0 "代表表記: / "
゚ ; ゚ 特殊 1 記号 5 * 0 * 0 "顔文字"
@ ゚ ゚ ゚ 特殊 1 記号 5 * 0 * 0 "顔文字"
@ ゚ Д ゚ 特殊 1 記号 5 * 0 * 0 "顔文字"
@ ゚ !! ゚ 特殊 1 記号 5 * 0 * 0 "顔文字"

固有名詞である”野獣先輩”がjuman++で認識されて処理されていることが分かります.しかし,顔文字の認識がうまくいってないです.辞書へはneologd辞書のまんまの半角で登録したのがダメだったのかな...

kytea

train-kyteaで次のように表示されます.

Scanning dictionaries and corpora for vocabulary
Reading corpus from train.txt  done (14 lines)
Reading dictionary from kytea-unidic-user-dict.txt  WARNING - empty training data specified.
Building dictionary index done!
Creating word segmentation features  done!
Building classifier  done!
Creating tagging features (tag 1) done!
Training local tag classifiers done!
Creating tagging features (tag 2) done!
Training local tag classifiers done!
Printing model to train.model done!

この後,この結果で形態素解析したい場合はkytea -nowsとコマンド入力してください.kyteaだとモデル学習してない通常のkytea状態での形態素解析になります.
また,WARNING - empty training data specifiedとあるように,用意したコーパスが不十分なようで,滅茶苦茶な形態素解析になります.例えば,

$ kytea
野獣先輩と海
野獣/名詞/やじゅう 先輩/名詞/せんぱい と/助詞/と 海/名詞/うみ
$ kytea -nows
野獣先輩と海
野獣先輩と海/URL/のけものさきはいとうみ

という感じ.コーパスも合うものを用意または自作するしかないようですね...いい塩梅の学習用コーパスがあれば頂きたいですね~

参考