かんちゃんの備忘録

プログラミングや言語処理、ガジェットなど個人の備忘録です。(メモ書き+α)

MeCabの使い方の備忘録

Sansan Advent Calendar 2018 の1日目の記事です。

いつもお世話になっているMeCabについての備忘録です。

インストール、辞書、辞書整備、Pythonやシェルでの取り扱いまで、使い方をまとめます。 マニュアル読めば分かるよ!というかたは公式マニュアルが充実しているのでそちらを読むのがいいかと思います。

MeCabとは

MeCab(和布蕪)とは2006年から開発されているオープンソース形態素解析器です。 動作が非常に高速で、辞書の配布や辞書の作成ができるため広く利用されています。

テキスト変換器として設計されているため、例えばひらがなからカタカナへの変換器のように、形態素解析以外の用途でも利用できます。

オープンソース形態素解析器を利用の観点からおおざっぱに比較します。(ほんとうにおおざっぱです、よく知らないところは?です)

MeCab JUMAN++ JUMAN Sudachi kytea
解析速度 ×
辞書整備 ?
未知語処理 ◎(自分で処理を記述できる)
自分で学習 ? ? ?
表記ゆれ △(辞書依存) ×

ざっくりと自分なりの選定基準を書きます。

  • とりあえず 生ビール MeCab
  • 速度は遅くて良いので、高精度な解析とリッチな付加情報が欲しいときは、JUMAN++
  • JUMAN++よりもう少し早く、リッチな付加情報が欲しいときは、JUMAN
  • 表記ゆれを解消したいときは、Sudachi
  • 単語の単位を複数考慮したいときは、Sudachi
  • 一部分をアノテーションする気力があるときは、kytea

形態素解析器という観点だけでは言えないこともあり、例えば検索向けだと再現率を高めるために、短い単語の単位を採用しおている UniDic のような辞書を選ぶことが重要になってきます。

インストール

Windowsはどうにか頑張ってください汗

exeファイルを実行すると、 MeCabコンパイル済みの辞書が導入されるはずです。

Linuxでソースからビルド

Ubuntu 16.04 で作業しています。 例えばGCPのプリセットで選べるUbuntuのようにミニマムな構成だと、ビルドツールが入っていませんので、次のコマンドでインストールしておきます。

$ sudo apt install g++ make

まずは作業用ディレクトリを作成し、そこにダウンロードします。

# 作業用のディレクトリ mecab を作成し、そこに移動
~$ mkdir mecab && cd $_
# mecab 本体のダウンロード
~/mecab$ wget "https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7cENtOXlicTFaRUE" -0 mecab-0.996.tar.gz
# mecab-ipadic辞書のダウンロード
~_mecab$ wget "https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7MWVlSDBCSXZMTXM" -O mec
ab-ipadic.tar.gz

MeCabのビルドとインストールを行います。

# tar.gz の展開
~/mecab$ tar zxvf mecab-0.996.tar.gz
# ディレクトリの移動
~/mecab$ cd mecab-0.996
# utf8限定モードでビルドを設定
~/mecab/mecab-0.996$ ./configure --enable-utf8-only
# ビルド
~/mecab/mecab-0.996$ make
# 正常にビルドできたか確認
~/mecab/mecab-0.996$ make check
# 標準のインストール先である /usr/local 以下にインストール
~/mecab/mecab-0.996$ sudo make install
# 共有ライブラリの更新
~/mecab/mecab-0.996$ sudo ldconfig

辞書をインストールします。

# tar.gz の展開
~/mecab$ tar zxvf mecab-ipadic.tar.gz
# ディレクトリの移動
~/mecab$ cd mecab-ipadic-2.7.0-20070801
# UTF8でビルドを行う設定でビルド設定を作成
~/mecab/mecab-ipadic-2.7.0-20070801$ ./configure --with-charset=utf8
# ビルド
~/mecab/mecab-ipadic-2.7.0-20070801$ make
# 標準のインストール先である /usr/local/lib_mecab 以下にインストール
~/mecab/mecab-ipadic-2.7.0-20070801$ sudo make install
$ echo "MeCabで始める形態素解析" | mecab
MeCab   名詞,一般,*,*,*,*,*
で      助詞,格助詞,一般,*,*,*,で,デ,デ
始める  動詞,自立,*,*,一段,基本形,始める,ハジメル,ハジメル
形態素  名詞,一般,*,*,*,*,形態素,ケイタイソ,ケイタイソ
解析    名詞,サ変接続,*,*,*,*,解析,カイセキ,カイセキ
EOS

パッケージマネージャ

Debian向けのパッケージマネージャである APT のレポジトリには、mecabと辞書が登録されています。 実は apt コマンドで簡単に導入できます。

$ sudo apt install mecab libmecab-dev mecab-ipadic-utf8
$ echo "MeCabで始める形態素解析" | mecab
MeCab   名詞,一般,*,*,*,*,*
で      助詞,格助詞,一般,*,*,*,で,デ,デ
始める  動詞,自立,*,*,一段,基本形,始める,ハジメル,ハジメル
形態素  名詞,一般,*,*,*,*,形態素,ケイタイソ,ケイタイソ
解析    名詞,サ変接続,*,*,*,*,解析,カイセキ,カイセキ
EOS

Docker

後にPythonバインディングを利用するので、PythonのコンテナをベースにしてソースからMeCabを導入します。

Dockerfile

FROM python:3.6

WORKDIR /work

RUN git clone --depth 1 https://github.com/taku910/mecab.git

RUN cd /work/mecab/mecab && \
    ./configure --enable-utf8-only && \
    make && \
    make install && \
    ldconfig && \
    cd /work/mecab/mecab-ipadic && \
    ./configure --with-charset=utf8 && \
    make && \
    make install

ビルドしてコンテナを実行します。

$ docker build . -t mecab-python
$ docker run --rm -t mecab-python /bin/bash
# echo "MeCabで始める形態素解析" | mecab
MeCab   名詞,一般,*,*,*,*,*
で      助詞,格助詞,一般,*,*,*,で,デ,デ
始める  動詞,自立,*,*,一段,基本形,始める,ハジメル,ハジメル
形態素  名詞,一般,*,*,*,*,形態素,ケイタイソ,ケイタイソ
解析    名詞,サ変接続,*,*,*,*,解析,カイセキ,カイセキ
EOS

基本的な使い方

標準入力から解析

MeCab は、標準入力されたテキストを解析します。 標準入力の解析には2パターンあり、 mecab コマンドにより入力する方法と、パイプにより標準入力する方法があります。

$ mecab
MeCabで始める形態素解析
MeCab   名詞,一般,*,*,*,*,*
で      助詞,格助詞,一般,*,*,*,で,デ,デ
始める  動詞,自立,*,*,一段,基本形,始める,ハジメル,ハジメル
形態素  名詞,一般,*,*,*,*,形態素,ケイタイソ,ケイタイソ
解析    名詞,サ変接続,*,*,*,*,解析,カイセキ,カイセキ
EOS

標準入力での解析は、先ほどから実は使っています。

$ docker build . -t mecab-python
$ docker run --rm -t mecab-python /bin/bash
# echo "MeCabで始める形態素解析" | mecab
MeCab   名詞,一般,*,*,*,*,*
で      助詞,格助詞,一般,*,*,*,で,デ,デ
始める  動詞,自立,*,*,一段,基本形,始める,ハジメル,ハジメル
形態素  名詞,一般,*,*,*,*,形態素,ケイタイソ,ケイタイソ
解析    名詞,サ変接続,*,*,*,*,解析,カイセキ,カイセキ
EOS

ファイルを引数で与えて解析もできますが、標準入力のほうが連携しやすいため、使ったことがありません。

出力フォーマット

出力フォーマットを -O オプションで選べます。 分かち書きフォーマットは標準であるため、使ってみます。

$ echo "MeCabで始める形態素解析" | mecab -Owakati
MeCab で 始める 形態素 解析

自分でフォーマットを定義することができます。 dicrcもしくは、オプションで与えることができます。 オプションが手軽ですのでそちらを紹介します。

次のKWICしやすいフォーマットがおすすめです。

qiita.com

$ echo "MeCabで始める形態素解析"
 | mecab --node-format="%M/%f[0] " --eos-format=""
MeCab/名詞 で/助詞 始める/動詞 形態素/名詞 解析/名詞
$ echo "MeCabで始める形態素解析" | mecab --node-format="%M/%f[0] " --eos-format="" | 
grep -oE "\S+/名詞"
MeCab/名詞
形態素/名詞
解析/名詞

辞書

MeCabで使える辞書でメジャーなものを簡単に紹介します。

  • IPA辞書
    • 広く使われているため、 Word2Vec などの学習済みモデルの分割単位であることが多い
  • Juman辞書
    • Jumanの辞書。私はあまり使ったこと無くよく知らない
  • UniDic辞書
    • UniDicの短単位で分割できる辞書。漢語・和語情報や語彙素など情報が豊富
  • mecab-ipadic-neologd
    • IPA辞書をベースにしたもので、固有表現や新語を取り込み続けている

辞書整備

MeCabはシステム辞書とユーザ辞書を持っています。 システム辞書のビルドには数十秒要しますが、内部実装の都合だとは思いますが解析速度が落ちません。 ユーザ辞書は量によりますがビルドが直ぐにおわります。

公式マニュアルに詳しく掲載されています。

何か単語に対してタグを付与したい場合には、辞書に項目を増やすことができます。 辞書のフォーマットは次のようになっています。

うれしい,43,43,6762,形容詞,自立,*,*,形容詞・イ段,基本形,うれしい,ウレシイ,ウレシイ

これに対して、例えば極性をあらかじめ辞書に組み込むとしましょう。 次のように、一列追加することで解析結果に紐付けることができます。

うれしい,43,43,6762,形容詞,自立,*,*,形容詞・イ段,基本形,うれしい,ウレシイ,ウレシイ,ポジ

解析はあらかじめ学習されたスコアにより導出されているため、それに紐付く情報はいくら付与しても影響しないということです。

新語を追加する場合のコストの話もあります。 経験則で申し訳ないですが、例えば人名を追加する場合は、辞書に既に含まれている人名のコストを取得し、その平均を安直に付与します。

他には文字数でコストを調整します。 形態素解析器は、コストが最も小さくなるような系列を出力します。 経験的に長い文字列の一致は固有表現であることが多いため、文字列が長いほどコストを低くすることで、正しい出力を得やすいです。 短い文字列は、同じ表層形でそもそもの辞書に普通名詞として存在している場合が多いため、追加してもあまり意味がないかもしれません。

コストについては、次のサイトが参考になるかと思います。

日本テレビ東京で学ぶMeCabのコスト計算 | mwSoft

abicky.net

Pythonバインディング

標準のバインディングPython 2系向けに開発されているため、Python 3系で利用する場合は mecab-python3 モジュールを用います。

現在の最新版(0.996.1)は SWIG 周りがうまく動かないため、バージョン 0.7 がいいかと思います。

$ pip install mecab-python3==0.7

使い方ですが、よくこのように使っています。

import MeCab

from collections import namedtuple


class MeCabTokenizer:
    # 自分が使いたい項目を namedtuple で取り扱う
    Morpheme = namedtuple("Morpheme", "surface pos pos_s1 pos_s2")

    def __init__(self, **kwargs):
        self.tagger = MeCab.Tagger(**kwargs)
        # mecab-python3のSWIGのバグを回避
        self.tagger.parse("Initialize")

    def iter_token(self, text):
        node = self.tagger.parseToNode(text)
        node = node.next
        while node.next:
            yield self.Morpheme(node.surface, *node.feature.split(",")[:3])
            node = node.next

イテレータが扱いづらければ、トークンのリストを返してもいいと思います。

他には少しややこしいコードですが、 MeCab の Nodeと同じように prev や next を利用できるようにラッパーを書くのも、扱いやすくする一つのコツかと思います。

github.com

おわりに

雑多になりましたが、MeCabを使っていてよく利用する機能についてまとめました。 (途中ちょっと疲れて説明が雑になっている部分もあります。。)

本当に神様のようなツールだと思います。