ゆるふわ自然言語処理（その１）MeCab で形態素解析

（追記：2023/02/03）この記事、全体的に古いです。しかもここで紹介している repository は古いので既に削除しました。[こっち](https://qiita.com/tetutaro/items/c3ab17b5e949648d0c4f)の記事を参照してください。
<hr>
友人の息子が Python を習いたいと言う。なんで Python を習いたいかと言うと機械学習がしたいと。機械学習の何がしたいかというと、自然言語処理がしたいのだと。中学生なのに。チュウガクセイのムスコなのに。ご立派なムスコでいらっしゃる。

せっかくなので、我流で申し訳ないが、自然言語処理ってどうやるのかをゆるふわに解説していきたいと思う。キーワードはゆるふわ。

ちなみに Python は解説しない。そっちはいくらでも教材等があるので。

# シリーズ目次

* MeCab で形態素解析　←　イマココ
* [fastText で単語分散表現](https://qiita.com/tetutaro/items/2c7fbedce21d670373cb)
* [Shallow Learningで文書分類](https://qiita.com/tetutaro/items/6050a878fd2c4e82ee35)

# 形態素解析

日本語の NLP（Natural Language Processing：自然言語処理）の第一歩は、形態素解析。日本語は、英語などとは違って、単語と単語の間に空白等の区切りが無い。なので、日本語の文章を解析するためには、まず文章を単語に区切らなきゃいけない。

形態素とは何か、単語と形態素は何が違うのか、という疑問が初っ端から出てくると思う。

[Wikipedia](https://ja.wikipedia.org/wiki/%E5%BD%A2%E6%85%8B%E7%B4%A0) によると、「それ以上分解したら意味をなさなくなるところまで分割して抽出された、 音素のまとまりの1つ1つ」とある。

Wikipedia の例だが、「雨宿り」という言葉は、普通これでひとつの単語として良い。しかし、もっと言えば「雨」「宿り」というように分けられる。「雨」が降っているので、軒下等に「宿」ってやり過ごすのだなと。このように、この２つに分けても意味が分からなくなることはない。でも、これ以上分割すると、もはや意味が分からなくなる。

だから、「雨宿り」は単語で、「雨」と「宿り」は形態素。形態素は基本的に単語よりも細かい分け方。

ただまぁ、こんな厳密に考えてたら逆に分かり難くなっちゃうんで、「形態素はまぁ単語と同じようなもん」と思えば良い。以降も「形態素」の意味で「単語」と書くから。適当に。（ゆるふわ）

そして形態素には必ず品詞（名詞とか動詞とか）が付く。これも一緒に判断しなきゃいけない。

# MeCab

この形態素解析をしてくれるツールが [MeCab](https://taku910.github.io/mecab/)。非常に素晴らしいツールなので、使うたびに工藤拓さんの方面に向かって五体投地をするほど（お会いしたことは無いけど）。形態素解析するツールは他にも [kuromoji](https://www.atilika.com/ja/kuromoji/)、[Juman++](https://github.com/ku-nlp/jumanpp)、[Sudachi](https://github.com/WorksApplications/Sudachi) とかあるけど、私はもっぱら MeCab 派。

MeCab は [CRF](https://ja.wikipedia.org/wiki/%E6%9D%A1%E4%BB%B6%E4%BB%98%E3%81%8D%E7%A2%BA%E7%8E%87%E5%A0%B4) という機械学習の一種を使って形態素解析をするのだが、CRF について理解する必要はない。理解しなくても使えるから！（ゆるふわ）

なんとな〜く説明する。MeCab は辞書を持っていて、文章の先頭から辞書に照らし合わせて単語に区切っていく。そうすると、いくつか区切るパターンが出来上がる。

（例）「山下の車を山下車とする」

* 山下 - の - 車 - を - 山下 - 車 - と - する
* 山 - 下 - の - 車 - を - 山 - 下車 - とす - る

（区切り方はもっとあるだろうけど）

MeCab はあらかじめ学習した、左右の単語から見て、その単語がそこに出現する時のコスト（生成コスト）を持っている。いくつもある分割パターンの中から、文章全体としてコストが最も小さくなるパターンを正解とする。

ここらへんをちゃんと勉強したい場合は、[工藤拓さんの本](https://www.amazon.co.jp/dp/4764905779/)を読めば良いと思う。

この時に使う単語の一覧や、その品詞・コスト等が載っているものを「形態素解析辞書」もしくは単純に「辞書」と言う。だから MeCab を使う上で重要になるのは、「どの辞書を使うか」という点になる。

# MeCab の辞書

MeCab の辞書で有名なものは IPA 辞書と JUMAN 辞書である（他にもあるけど）。どっちを使っても良いけど、[品詞体系](https://www.unixuser.org/~euske/doc/postag/)がちょっと違うので、注意が必要。ここでは IPA 辞書を使うものとする。

（一般的に、単語の変化型や語尾を単語に含めてしまいたい場合は JUMAN 辞書の方が便利）

IPA 辞書は日本語の基本的な単語がしっかり載っていて、「まさに形態素！」って感じに分割してくれる。

しかしそれだけだと上手く行かない場合もある。例えば Twitter のつぶやきを解析する時とか、砕けた感じの文章、新しい単語が出てくる文章だとメタメタになってしまう。

これらを解決するのが [IPA NEologd](https://github.com/neologd/mecab-ipadic-neologd)。日本語 Wikipedia から単語を拾って学習し、辞書に取り込んでくれている。再び五体投地。

ただ、NEologd をそのまま使うと、新しい単語に引っ張られちゃって、ビシッと形態素に分割する感が無くなってしまう。（あくまで「感じ」）

そこで、IPA 辞書に NEologd のデータをブッコむことにする。

どうやってやるかって？もうやってますよ。

https://github.com/tetutaro/mecab_dictionary/

これで良い感じになった気がする。（気がするだけ）

# MeCab の使い方

参考までに、上の私の作った MeCab 辞書を使って形態素解析をする方法を解説する。

## MeCab のインストール

まずは MeCab をインストールしないと始まらない。

Mac OS ならば `> brew install mecab` で出来る。

Homebrew のインストールは[Homebrewオヒサル](https://brew.sh/index_ja)を参照のこと。

Linux は、Ubuntu など Debian　系のディストリビューションならば apt で入るはず。CentOS などの RedHat 系ならば yum。他は知らん（ゆるふわ）。

## 辞書の作り方

辞書の作り方は、上記の repository を clone したら、その clone したディレクトリで `> ./make_dictionary.sh` と叩くだけ。ソースをダウンロードしたりコンパイルするので、そこそこの時間がかかる。

この辞書には、自分で定義した単語を追加することもできる。`make_dictionary.sh` する前に、userdic.csv に追加するだけ。書き方は README にも書いたし、サンプルとして適当な単語を登録してある。

## 使ってみる

後は `make_dictionary.sh` で作られた `mecab_ipadic` ディレクトリを、辞書のパスとして MeCab に `-d` オプションで渡すだけ。

コマンドラインから MeCab を使う場合のサンプルとして、MeCab の叩き方とその結果を以下に示す。

```
> echo "太郎と丸太郎とキンタロー。が共にアズガルドに向かう" | mecab -d mecab_ipadic
太郎  名詞,固有名詞,人名,名,*,*,太郎,タロウ,タロー,ipadic
と  助詞,並立助詞,*,*,*,*,と,ト,ト,ipadic
丸太郎  名詞,固有名詞,人名,名,*,*,丸太郎,マルタロウ,マルタロー,user
と  助詞,並立助詞,*,*,*,*,と,ト,ト,ipadic
キンタロー。    名詞,固有名詞,一般,*,*,*,キンタロー。,キンタロー,キンタロー,ipadic-neologd
が  助詞,格助詞,一般,*,*,*,が,ガ,ガ,ipadic
共に    副詞,一般,*,*,*,*,共に,トモニ,トモニ,ipadic
アズガルド  名詞,一般,*,*,*,*,*
に	  助詞,格助詞,一般,*,*,*,に,ニ,ニ,ipadic
向かう  動詞,自立,*,*,五段・ワ行促音便,基本形,向かう,ムカウ,ムカウ,ipadic
EOS
```

各行が分割された形態素を表していて、タブの左が文章から分割された形態素のそのままの形（表層型という）。タブの右がカンマ区切りで表された形態素の様々な特徴（素性という）。

## 出力の設定と理解

この出力をコントロールする方法は、[このページ](https://taku910.github.io/mecab/format.html) に定義が書いてあるので、MeCab のオプションや mecabrc を作って指定する。デフォルトの値は `> mecab -P` で確認できる。

素性の各要素が何を表しているかは、[このページ](https://taku910.github.io/mecab/dic.html)から読み取れるのだが、私の repository で作った辞書は要素をひとつ追加しているので、以下の定義になる。

```
品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用型,活用形,原形,読み,発音,辞書
```

要するに、IPA に IPA NEologd とユーザー辞書を追加しているので、それが分かるようになっている。

実際に上記の例だと、「キンタロー。」は IPA NEologd 辞書から、「丸太郎」はユーザー辞書を用いて判断したもので、それ以外の形態素は IPA 辞書を用いて判断したものであることが分かる。

# MeCab を Python から使う

確認として上記コマンドを使うことはあるだろうけど、本当に何かをしたい場合は Python から叩くことになるだろう。

## 準備

Python から MeCab を使うためには、[mecab-python3](https://pypi.org/project/mecab-python3/) を使う。もちろん Python は 3.x 系を使うのだよ。

mecab-python3 のインストールは `> pip install mecab-python3`。本当は Python の仮想環境の設定とかあるのだが、それはここでは省略。

## 使い方

基本的には以下のように使うのが簡単で良い。

```
from MeCab import Tagger

tagger = Tagger('コマンドのMeCabに渡すオプションの文字列')
nodes = tagger.parse('形態素解析したい文章')
for node in nodes.splitlines():
    node = node.strip()
    if node == 'EOS':
        # EOS(End Of Sentence) は文章の終わりを表す
        break
    # surface は表層型、features_strは素性がCSV形式になったもの
    surface, features_str = node.split('\t', 1)
    features = features_str.split(',')
    ...様々な処理...
```

上記の例はデフォルトの出力形式の場合で、オプションや mecabrc で出力形式を変更した場合は上記の限りではない。

## サンプル実装

私の repository にサンプル実装を置いといたよ。

https://github.com/tetutaro/mecab_dictionary/blob/master/mecab.py

ここで作った辞書だけななくて、インストールした IPA辞書・JUMAN辞書・IPA NEologd 辞書にも対応しておいた。
ちなみに動かすには `neologdn` パッケージが必要。

作った辞書で動かす場合。

```
> echo "丸太郎は吾輩は猫であるをホゲランドで読んだ" | ./mecab.py
XXXX-XX-XX XX:XX:XX,XXX: INFO: loading local dictionary: mecab_ipadic
丸太郎(丸太郎)[マルタロウ] (0:3) 名詞,固有名詞,人名 user
は(は)[ハ] (3:4) 助詞,係助詞,* ipadic
吾輩は猫である(吾輩は猫である)[ワガハイハネコデアル] (4:11) 名詞,固有名詞,一般 ipadic-neologd
を(を)[ヲ] (11:12) 助詞,格助詞,一般 ipadic
ホゲランド(UNK)[UNK] (12:17) 名詞,一般,*
で(で)[デ] (17:18) 助詞,格助詞,一般 ipadic
読ん(読む)[ヨン] (18:20) 動詞,自立,* ipadic
だ(だ)[ダ] (20:21) 助動詞,*,* ipadic
```

辞書のパスや名前を `-d` オプションに指定することで、他のディレクトリにある辞書や、インストール済みの IPA 辞書・JUMAN 辞書・IPA NEologd 辞書を使うことも出来るようにしてあります。
（もちろんこれらの辞書がインストール済みであることが必要）

IPA 辞書の場合

```
> echo "丸太郎は吾輩は猫であるをホゲランドで読んだ" | ./mecab.py -d ipa
XXXX-XX-XX XX:XX:XX,XXX: INFO: loading installed dictionary: ipa
丸(丸)[マル] (0:1) 名詞,固有名詞,人名
太郎(太郎)[タロウ] (1:3) 名詞,固有名詞,人名
は(は)[ハ] (3:4) 助詞,係助詞,*
吾輩(吾輩)[ワガハイ] (4:6) 名詞,代名詞,一般
は(は)[ハ] (6:7) 助詞,係助詞,*
猫(猫)[ネコ] (7:8) 名詞,一般,*
で(だ)[デ] (8:9) 助動詞,*,*
ある(ある)[アル] (9:11) 助動詞,*,*
を(を)[ヲ] (11:12) 助詞,格助詞,一般
ホゲランド(UNK)[UNK] (12:17) 名詞,一般,*
で(で)[デ] (17:18) 助詞,格助詞,一般
読ん(読む)[ヨン] (18:20) 動詞,自立,*
だ(だ)[ダ] (20:21) 助動詞,*,*
```

JUMAN 辞書の場合

```
> echo "丸太郎は吾輩は猫であるをホゲランドで読んだ" | ./mecab.py -d juman
XXXX-XX-XX XX:XX:XX,XXX: INFO: loading installed dictionary: juman
丸(丸)[まる] (0:1) 名詞,普通名詞,*
太郎(太郎)[たろう] (1:3) 名詞,人名,*
は(は)[は] (3:4) 助詞,副助詞,*
吾輩(吾輩)[わがはい] (4:6) 名詞,普通名詞,*
は(は)[は] (6:7) 助詞,副助詞,*
猫(猫)[ねこ] (7:8) 名詞,普通名詞,*
である(だ)[である] (8:11) 判定詞,*,判定詞
を(を)[を] (11:12) 助詞,格助詞,*
ホゲランド(UNK)[UNK] (12:17) 名詞,普通名詞,*
で(で)[で] (17:18) 助詞,格助詞,*
読んだ(読む)[よんだ] (18:21) 動詞,*,子音動詞マ行
```

IPA NEologd 辞書の場合

```
> echo "丸太郎は吾輩は猫であるをホゲランドで読んだ" | ./mecab.py -d neologd
XXXX-XX-XX XX:XX:XX,XXX: INFO: loading installed dictionary: neologd
丸(丸)[マル] (0:1) 名詞,固有名詞,人名
太郎(太郎)[タロウ] (1:3) 名詞,固有名詞,人名
は(は)[ハ] (3:4) 助詞,係助詞,*
吾輩は猫である(吾輩は猫である)[ワガハイハネコデアル] (4:11) 名詞,固有名詞,一般
を(を)[ヲ] (11:12) 助詞,格助詞,一般
ホゲランド(UNK)[UNK] (12:17) 名詞,一般,*
で(で)[デ] (17:18) 助詞,格助詞,一般
読ん(読む)[ヨン] (18:20) 動詞,自立,*
だ(だ)[ダ] (20:21) 助動詞,*,*
```

# その１はこれで終わり
次は単語分散表現。