形態素解析エンジン「MeCab」で遊んでみる

-   形態素解析とは

      文を辞書データをもとに形態素（Morpheme、意味を持つ最小単位）に分割し、それぞれの形態素の品詞などを判別すること。

-   MeCabとは

      オープンソースの形態素解析エンジン。perl, ruby, python, Javaなどからも利用できる。

# 実行環境

-   Ubuntu(WSL2)
-   Python 3.8.9

# 準備

## Mecabインストール

まずはMecabをインストールする。

[公式サイト](https://taku910.github.io/mecab/)からもインストールできるが、ubuntuの場合aptコマンドでインストールできる。

```bash
sudo apt install mecab
```

以下のコマンドが動けば正しくインストールできている。

```bash
$ echo "すもももももももものうち" | mecab
すもも  名詞,普通名詞,*,*,すもも,すもも,自動獲得:テキスト
も      助詞,副助詞,*,*,も,も,*
もも    名詞,普通名詞,*,*,もも,もも,代表表記:桃/もも 漢字読み:訓 カテゴリ:植物;人工物-食べ物 ドメイン:料理・食事
も      助詞,副助詞,*,*,も,も,*
もも    名詞,普通名詞,*,*,もも,もも,代表表記:桃/もも 漢字読み:訓 カテゴリ:植物;人工物-食べ物 ドメイン:料理・食事
の      助詞,接続助詞,*,*,の,の,*
うち    名詞,副詞的名詞,*,*,うち,うち,代表表記:うち/うち
EOS
```

## mecab-python3をインストール

次にPythonからmecabを実行するための[mecab-python3](https://pypi.org/project/mecab-python3/)をインストールする。

```bash
$ pip install mecab-python3
```

以下のコードが動けばOk。

```python
import MeCab
tagger = MeCab.Tagger()
result = tagger.parse('すもももももももものうち')
print(result)

# mecabを直接実行したときと同じ結果が得られる
# すもも  名詞,普通名詞,*,*,すもも,すもも,自動獲得:テキスト
# も      助詞,副助詞,*,*,も,も,*
# もも    名詞,普通名詞,*,*,もも,もも,代表表記:桃/もも 漢字読み:訓 カテゴリ:植物;人工物-食べ物 ドメイン:料理・食事
# も      助詞,副助詞,*,*,も,も,*
# もも    名詞,普通名詞,*,*,もも,もも,代表表記:桃/もも 漢字読み:訓 カテゴリ:植物;人工物-食べ物 ドメイン:料理・食事
# の      助詞,接続助詞,*,*,の,の,*
# うち    名詞,副詞的名詞,*,*,うち,うち,代表表記:うち/うち
# EOS
```

### エラーが出る場合

ubuntuの場合、Pythonでmecabを実行したときに以下のエラーが発生することがある。

```python
error message: [ifs] no such file or directory: /usr/local/etc/mecabrc
```

aptでMeCabをインストールするとmecabrcが想定と異なるパスに作成される。そのため正しいパスを指定することで解消する。

```python
# オプションで指定
tagger = MeCab.Tagger('-r /etc/mecabrc')
```

```bash
# 環境変数でも指定できる
export MECABRC="/etc/mecabrc"
```

# 辞書を変えてみる

## デフォルト辞書の確認

```bash
# mecabrcを確認
$ cat /etc/mecabrc
;
; Configuration file of MeCab
;
; $Id: mecabrc.in,v 1.3 2006/05/29 15:36:08 taku-ku Exp $;
;
dicdir = /var/lib/mecab/dic/debian

; userdic = /home/foo/bar/user.dic

; output-format-type = wakati
; input-buffer-size = 8192

; node-format = %m\n
; bos-format = %S\n
; eos-format = EOS\n

# mecabrc内のdicdirのリンク先を確認
$ ls -l /var/lib/mecab/dic/debian
lrwxrwxrwx 1 root root 34 Apr 15 09:59 /var/lib/mecab/dic/debian -> /etc/alternatives/mecab-dictionary
$ ls -l /etc/alternatives/mecab-dictionary
lrwxrwxrwx 1 root root 30 Apr 15 16:36 /etc/alternatives/mecab-dictionary -> /var/lib/mecab/dic/juman-utf8
```

デフォルトの辞書を切り替える場合は`/etc/mecabrc`の`dicdir`を直接書き換えるか、`sudo update-alternatives --config mecab-dictionary`を実行して`/etc/alternatives/mecab-dictionary`のリンク先を変更する。

## Juman辞書

aptでMeCabインストールした場合、デフォルトでJuman辞書が使われる。

Juman辞書の出力フォーマットは以下の通り。（正確な情報を見つけられなかったので、推測もはいっています）

    表層形\t品詞大分類,品詞細分類,活用型,活用形,見出し語,読み,意味情報

例）

```bash
$ echo '上海ガニ食べたい' | mecab
上海    名詞,地名,*,*,上海,しゃんはい,代表表記:上海/しゃんはい 地名:国:中国:市
ガニ    名詞,人名,*,*,*,*,*
食べ    動詞,*,母音動詞,未然形,食べる,たべ,代表表記:食べる/たべる ドメイン:料理・食事
たい    接尾辞,形容詞性述語接尾辞,イ形容詞アウオ段,基本形,たい,たい,代表表記:たい/たい
EOS
```

## IPA辞書

aptでインストールすると自動でIPA辞書が使用されるようになる。

```bash
$ sudo apt install ipadic-utf8
```

IPA辞書の出力フォーマットは以下の通り。

    表層形\t品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用型,活用形,原形,読み,発音

Juman辞書で試した文と同じ文で形態素解析してみる。

```bash
$ echo '上海ガニ食べたい' | mecab
上海    名詞,固有名詞,地域,一般,*,*,上海,シャンハイ,シャンハイ
ガニ    名詞,接尾,一般,*,*,*,ガニ,ガニ,ガニ
食べ    動詞,自立,*,*,一段,連用形,食べる,タベ,タベ
たい    助動詞,*,*,*,特殊・タイ,基本形,たい,タイ,タイ
EOS
```

Juman辞書で解析した結果と異なる解析結果が得られる。

## mecab-ipadic-NEologd

Juman辞書、IPA辞書どちらを使っても`上海ガニ`は上海とガニに分割されてしまい正しく分割できていない。

そこで`mecab-ipadic-NEologd`を使ってみる。

`mecab-ipadic-NEologd`はWeb上の情報をもとに新語や固有表現をIPA辞書に追加したもの。

[GitHub - neologd/mecab-ipadic-neologd: Neologism dictionary based on the language resources on the Web for mecab-ipadic](https://github.com/neologd/mecab-ipadic-neologd)

`mecab-ipadic-NEologd`のインストールに必要となる`mecab-config`は、aptでインストールした環境ではパッケージを追加する必要があった。

```bash
$ sudo apt install libmecab-dev
```

インストールの手順はREADMEを参考に。

```bash
git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git 
cd mecab-ipadic-neologd
./bin/install-mecab-ipadic-neologd -n
```

先ほどと同じ文を解析してみる。

```bash
$ echo '上海ガニ食べたい' | mecab -d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd
上海ガニ        名詞,固有名詞,一般,*,*,*,上海ガニ,シャンハイガニ,シャンハイガニ
食べ    動詞,自立,*,*,一段,連用形,食べる,タベ,タベ
たい    助動詞,*,*,*,特殊・タイ,基本形,たい,タイ,タイ
EOS
```

`上海ガニ`が正しく分割されるようになった。

# 単語を追加してみる

NEologdを使えば多くの言葉を解析できるようになるが、それでも解析できない単語がある。

たとえばClubhouseを解析すると以下のような結果となる。

```bash
$ echo 'Clubhouse' | mecab -d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd
Clubhouse       名詞,固有名詞,組織,*,*,*,*
EOS
```

そこで自分で新しく辞書に単語を追加してみる。

## ユーザ辞書へ追加

MeCabでは既存の辞書にユーザが作成した辞書を追加する仕組みがある。

そこで`ipadic`をベースにユーザ辞書で単語を追加してみる。

### ipadicのソース

ユーザ辞書のコンパイルに必要となる`ipadic`のソースは、aptでipadic-utf8をインストールした場合`/usr/share/mecab/dic/ipadic/`に保存されている。直接指定して使うとエラーが発生したので作業ディレクトリにコピーしておく。

### モデルファイル

追加する単語のコスト値は、学習時に出力されたモデルファイルがあれば自動推定できるらしい。
ipadicのモデルファイルは[MeCabのサイト](https://taku910.github.io/mecab/dic.html)からダウンロードできる。ダウンロード、解凍して`mecab-ipadic.model`というファイル名で保存しておく。

### 追加する単語

追加する単語はcsvで定義する。フォーマットは`ipadic`に合わせる。

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

今回はClubhouseを定義した`userdic.csv`を作成する。
    
```
Clubhouse,,,,名詞,固有名詞,一般,*,*,*,Clubhouse,クラブハウス,クラブハウス
```

左文脈ID、右文脈ID、コストは空にしておくと自動で付与される。
`ipadic`のソースの文字コードと合わせる必要があるため、`EUC-JP`で作成すること。

### コンパイル

コンパイルは以下のコードで行う。

```bash
$ /lib/mecab/mecab-dict-index -m mecab-ipadic.model -d ipadic -u user.dic -f euc-jp -t utf-8 userdic.csv
```

-   \-m: モデルファイル
-   \-d: ソースフォルダ
-   \-u: ユーザ辞書の出力名
-   \-f: CSVの文字コード
-   \-t: ユーザ辞書の文字コード

作成されたユーザ辞書をMeCab実行時のオプションで渡すことで使用できる。

```bash
$ echo "Clubhouse" | mecab -u user.dic
Clubhouse       名詞,固有名詞,一般,*,*,*,Clubhouse,クラブハウス,クラブハウス
EOS
```

ユーザ辞書で追加した単語が得られることを確認できた。

## システム辞書へ追加

次は`ipadic`をベースに単語を追加してシステム辞書を作成してみる。
先ほどコピーした`ipadic`フォルダをベースに使う。

システム辞書を作るときは、追加するCSVの文脈IDやコストの計算を事前に行っておく必要がある。

以下のコマンドで`userdic.csv`から文脈IDやコスト値を埋めた新しいCSVファイル`User.csv`がipadicフォルダに作られる。

```bash
$ /lib/mecab/mecab-dict-index -m mecab-ipadic.model -d ipadic -u ipadic/User.csv -f euc-jp -t utf-8 -a userdic.csv
```
### コンパイル

これで必要なデータはそろったので、コンパイルを行う。
ipadicディレクトリに移動し、コンパイルを実行する。

```bash
$ cd ipadic
$ /lib/mecab/mecab-dict-index -m mecab-ipadic.model -d ipadic -u ipadic/User.csv -f euc-jp -t utf-8 -a userdic.csv
```

コンパイルを行ったディレクトリを指定することで新しいシステム辞書を使うことができる。

```bash
$ echo "Clubhouse" | mecab -d ipadic
Clubhouse       名詞,固有名詞,一般,*,*,*,Clubhouse,クラブハウス,クラブハウス
EOS
```

ユーザ辞書を追加したときと同じ結果が得られた。