素人の言語処理100本ノック:30


[言語処理100本ノック 2015](http://www.cl.ecei.tohoku.ac.jp/nlp100/)の挑戦記録です。環境はUbuntu 16.04 LTS ＋ Python 3.5.2 \:\: Anaconda 4.1.1 (64-bit)です。過去のノックの一覧は[こちら](http://qiita.com/segavvy/items/fb50ba8097d59475f760)からどうぞ。

## 第4章: 形態素解析
>夏目漱石の小説『吾輩は猫である』の文章（neko.txt）をMeCabを使って形態素解析し，その結果をneko.txt.mecabというファイルに保存せよ．このファイルを用いて，以下の問に対応するプログラムを実装せよ．
>
>なお，問題37, 38, 39はmatplotlibもしくはGnuplotを用いるとよい．

###30. 形態素解析結果の読み込み
>形態素解析結果（neko.txt.mecab）を読み込むプログラムを実装せよ．ただし，各形態素は表層形（surface），基本形（base），品詞（pos），品詞細分類1（pos1）をキーとするマッピング型に格納し，1文を形態素（マッピング型）のリストとして表現せよ．第4章の残りの問題では，ここで作ったプログラムを活用せよ．

####出来上がったコード：

```python:main.py
# coding: utf-8
import MeCab
fname = 'neko.txt'
fname_parsed = 'neko.txt.mecab'


def parse_neko():
	'''「吾輩は猫である」を形態素解析
	「吾輩は猫である」(neko.txt)を形態素解析してneko.txt.mecabに保存する
	'''

	with open(fname) as data_file, \
			open(fname_parsed, mode='w') as out_file:

		mecab = MeCab.Tagger()
		out_file.write(mecab.parse(data_file.read()))


def neco_lines():
	'''「吾輩は猫である」の形態素解析結果のジェネレータ
	「吾輩は猫である」の形態素解析結果を順次読み込んで、各形態素を
	・表層形（surface）
	・基本形（base）
	・品詞（pos）
	・品詞細分類1（pos1）
	の4つをキーとする辞書に格納し、1文ずつ、この辞書のリストとして返す

	戻り値：
	1文の各形態素を辞書化したリスト
	'''
	with open(fname_parsed) as file_parsed:

		morphemes = []
		for line in file_parsed:

			# 表層形はtab区切り、それ以外は','区切りでバラす
			cols = line.split('\t')
			if(len(cols) < 2):
				raise StopIteration		# 区切りがなければ終了
			res_cols = cols[1].split(',')

			# 辞書作成、リストに追加
			morpheme = {
				'surface': cols[0],
				'base': res_cols[6],
				'pos': res_cols[0],
				'pos1': res_cols[1]
			}
			morphemes.append(morpheme)

			# 品詞細分類1が'句点'なら文の終わりと判定
			if res_cols[1] == '句点':
				yield morphemes
				morphemes = []


# 形態素解析
parse_neko()

# 1文ずつ辞書のリストを作成
lines = neco_lines()
for line in lines:
	print(line)
```

####実行結果：
まず、形態素解析結果のneko.txt.mecabです。長いので先頭50行の抜粋です。

```console:neko.txt.mecab（先頭50行）
一	名詞,数,*,*,*,*,一,イチ,イチ,,
　	記号,空白,*,*,*,*,　,　,　,,
吾輩	名詞,代名詞,一般,*,*,*,吾輩,ワガハイ,ワガハイ,,
は	助詞,係助詞,*,*,*,*,は,ハ,ワ,,
猫	名詞,一般,*,*,*,*,猫,ネコ,ネコ,,
で	助動詞,*,*,*,特殊・ダ,連用形,だ,デ,デ,,
ある	助動詞,*,*,*,五段・ラ行アル,基本形,ある,アル,アル,,
。	記号,句点,*,*,*,*,。,。,。,,
名前	名詞,一般,*,*,*,*,名前,ナマエ,ナマエ,,
は	助詞,係助詞,*,*,*,*,は,ハ,ワ,,
まだ	副詞,助詞類接続,*,*,*,*,まだ,マダ,マダ,,
無い	形容詞,自立,*,*,形容詞・アウオ段,基本形,無い,ナイ,ナイ,ない/無い,
。	記号,句点,*,*,*,*,。,。,。,,
　	記号,空白,*,*,*,*,　,　,　,,
どこ	名詞,代名詞,一般,*,*,*,どこ,ドコ,ドコ,,
で	助詞,格助詞,一般,*,*,*,で,デ,デ,,
生れ	動詞,自立,*,*,一段,連用形,生れる,ウマレ,ウマレ,うまれ/生まれ/生れ,
た	助動詞,*,*,*,特殊・タ,基本形,た,タ,タ,,
か	助詞,副助詞／並立助詞／終助詞,*,*,*,*,か,カ,カ,,
とんと	副詞,一般,*,*,*,*,とんと,トント,トント,,
見当	名詞,サ変接続,*,*,*,*,見当,ケントウ,ケントー,,
が	助詞,格助詞,一般,*,*,*,が,ガ,ガ,,
つか	動詞,自立,*,*,五段・カ行イ音便,未然形,つく,ツカ,ツカ,つか/着か,
ぬ	助動詞,*,*,*,特殊・ヌ,基本形,ぬ,ヌ,ヌ,,
。	記号,句点,*,*,*,*,。,。,。,,
何	名詞,代名詞,一般,*,*,*,何,ナニ,ナニ,,
でも	助詞,副助詞,*,*,*,*,でも,デモ,デモ,,
薄暗い	形容詞,自立,*,*,形容詞・アウオ段,基本形,薄暗い,ウスグライ,ウスグライ,うすぐらい/薄ぐらい/薄暗い,
じめじめ	副詞,一般,*,*,*,*,じめじめ,ジメジメ,ジメジメ,,
し	動詞,自立,*,*,サ変・スル,連用形,する,シ,シ,,
た	助動詞,*,*,*,特殊・タ,基本形,た,タ,タ,,
所	名詞,非自立,副詞可能,*,*,*,所,トコロ,トコロ,,
で	助詞,格助詞,一般,*,*,*,で,デ,デ,,
ニャーニャー	名詞,一般,*,*,*,*,*
泣い	動詞,自立,*,*,五段・カ行イ音便,連用タ接続,泣く,ナイ,ナイ,ない/哭い/泣い,
て	助詞,接続助詞,*,*,*,*,て,テ,テ,,
い	動詞,非自立,*,*,一段,連用形,いる,イ,イ,,
た	助動詞,*,*,*,特殊・タ,基本形,た,タ,タ,,
事	名詞,非自立,一般,*,*,*,事,コト,コト,,
だけ	助詞,副助詞,*,*,*,*,だけ,ダケ,ダケ,,
は	助詞,係助詞,*,*,*,*,は,ハ,ワ,,
記憶	名詞,サ変接続,*,*,*,*,記憶,キオク,キオク,,
し	動詞,自立,*,*,サ変・スル,連用形,する,シ,シ,,
て	助詞,接続助詞,*,*,*,*,て,テ,テ,,
いる	動詞,非自立,*,*,一段,基本形,いる,イル,イル,,
。	記号,句点,*,*,*,*,。,。,。,,
吾輩	名詞,代名詞,一般,*,*,*,吾輩,ワガハイ,ワガハイ,,
は	助詞,係助詞,*,*,*,*,は,ハ,ワ,,
ここ	名詞,代名詞,一般,*,*,*,ここ,ココ,ココ,,
で	助詞,格助詞,一般,*,*,*,で,デ,デ,,
```

ファイル全体は[GitHub](https://github.com/segavvy/nlp100_Python/tree/master/30)にアップしています。

続いて今回のプログラムの結果です。長いので先頭5文のみ抜粋です。

```console:端末（先頭5文）
[{'surface': '一', 'base': '一', 'pos': '名詞', 'pos1': '数'}, {'surface': '\u3000', 'base': '\u3000', 'pos': '記号', 'pos1': '空白'}, {'surface': '吾輩', 'base': '吾輩', 'pos': '名詞', 'pos1': '代名詞'}, {'surface': 'は', 'base': 'は', 'pos': '助詞', 'pos1': '係助詞'}, {'surface': '猫', 'base': '猫', 'pos': '名詞', 'pos1': '一般'}, {'surface': 'で', 'base': 'だ', 'pos': '助動詞', 'pos1': '*'}, {'surface': 'ある', 'base': 'ある', 'pos': '助動詞', 'pos1': '*'}, {'surface': '。', 'base': '。', 'pos': '記号', 'pos1': '句点'}]
[{'surface': '名前', 'base': '名前', 'pos': '名詞', 'pos1': '一般'}, {'surface': 'は', 'base': 'は', 'pos': '助詞', 'pos1': '係助詞'}, {'surface': 'まだ', 'base': 'まだ', 'pos': '副詞', 'pos1': '助詞類接続'}, {'surface': '無い', 'base': '無い', 'pos': '形容詞', 'pos1': '自立'}, {'surface': '。', 'base': '。', 'pos': '記号', 'pos1': '句点'}]
[{'surface': '\u3000', 'base': '\u3000', 'pos': '記号', 'pos1': '空白'}, {'surface': 'どこ', 'base': 'どこ', 'pos': '名詞', 'pos1': '代名詞'}, {'surface': 'で', 'base': 'で', 'pos': '助詞', 'pos1': '格助詞'}, {'surface': '生れ', 'base': '生れる', 'pos': '動詞', 'pos1': '自立'}, {'surface': 'た', 'base': 'た', 'pos': '助動詞', 'pos1': '*'}, {'surface': 'か', 'base': 'か', 'pos': '助詞', 'pos1': '副助詞／並立助詞／終助詞'}, {'surface': 'とんと', 'base': 'とんと', 'pos': '副詞', 'pos1': '一般'}, {'surface': '見当', 'base': '見当', 'pos': '名詞', 'pos1': 'サ変接続'}, {'surface': 'が', 'base': 'が', 'pos': '助詞', 'pos1': '格助詞'}, {'surface': 'つか', 'base': 'つく', 'pos': '動詞', 'pos1': '自立'}, {'surface': 'ぬ', 'base': 'ぬ', 'pos': '助動詞', 'pos1': '*'}, {'surface': '。', 'base': '。', 'pos': '記号', 'pos1': '句点'}]
[{'surface': '何', 'base': '何', 'pos': '名詞', 'pos1': '代名詞'}, {'surface': 'でも', 'base': 'でも', 'pos': '助詞', 'pos1': '副助詞'}, {'surface': '薄暗い', 'base': '薄暗い', 'pos': '形容詞', 'pos1': '自立'}, {'surface': 'じめじめ', 'base': 'じめじめ', 'pos': '副詞', 'pos1': '一般'}, {'surface': 'し', 'base': 'する', 'pos': '動詞', 'pos1': '自立'}, {'surface': 'た', 'base': 'た', 'pos': '助動詞', 'pos1': '*'}, {'surface': '所', 'base': '所', 'pos': '名詞', 'pos1': '非自立'}, {'surface': 'で', 'base': 'で', 'pos': '助詞', 'pos1': '格助詞'}, {'surface': 'ニャーニャー', 'base': '*\n', 'pos': '名詞', 'pos1': '一般'}, {'surface': '泣い', 'base': '泣く', 'pos': '動詞', 'pos1': '自立'}, {'surface': 'て', 'base': 'て', 'pos': '助詞', 'pos1': '接続助詞'}, {'surface': 'い', 'base': 'いる', 'pos': '動詞', 'pos1': '非自立'}, {'surface': 'た', 'base': 'た', 'pos': '助動詞', 'pos1': '*'}, {'surface': '事', 'base': '事', 'pos': '名詞', 'pos1': '非自立'}, {'surface': 'だけ', 'base': 'だけ', 'pos': '助詞', 'pos1': '副助詞'}, {'surface': 'は', 'base': 'は', 'pos': '助詞', 'pos1': '係助詞'}, {'surface': '記憶', 'base': '記憶', 'pos': '名詞', 'pos1': 'サ変接続'}, {'surface': 'し', 'base': 'する', 'pos': '動詞', 'pos1': '自立'}, {'surface': 'て', 'base': 'て', 'pos': '助詞', 'pos1': '接続助詞'}, {'surface': 'いる', 'base': 'いる', 'pos': '動詞', 'pos1': '非自立'}, {'surface': '。', 'base': '。', 'pos': '記号', 'pos1': '句点'}]
[{'surface': '吾輩', 'base': '吾輩', 'pos': '名詞', 'pos1': '代名詞'}, {'surface': 'は', 'base': 'は', 'pos': '助詞', 'pos1': '係助詞'}, {'surface': 'ここ', 'base': 'ここ', 'pos': '名詞', 'pos1': '代名詞'}, {'surface': 'で', 'base': 'で', 'pos': '助詞', 'pos1': '格助詞'}, {'surface': '始め', 'base': '始める', 'pos': '動詞', 'pos1': '自立'}, {'surface': 'て', 'base': 'て', 'pos': '助詞', 'pos1': '接続助詞'}, {'surface': '人間', 'base': '人間', 'pos': '名詞', 'pos1': '一般'}, {'surface': 'という', 'base': 'という', 'pos': '助詞', 'pos1': '格助詞'}, {'surface': 'もの', 'base': 'もの', 'pos': '名詞', 'pos1': '非自立'}, {'surface': 'を', 'base': 'を', 'pos': '助詞', 'pos1': '格助詞'}, {'surface': '見', 'base': '見る', 'pos': '動詞', 'pos1': '自立'}, {'surface': 'た', 'base': 'た', 'pos': '助動詞', 'pos1': '*'}, {'surface': '。', 'base': '。', 'pos': '記号', 'pos1': '句点'}]
```

辞書の中の並びは実行の度に変わるので（[ハッシュのランダム化](http://docs.python.jp/3/using/cmdline.html#cmdoption-R)によるものと思われます）ご注意ください。
こちらも、結果全体を確認したい方は[GitHub](https://github.com/segavvy/nlp100_Python/tree/master/30)をどうぞ。

###パッケージ管理システムの管理システムが欲しい...
問題に取り組む前に、まずMeCabなどのインストールが必要なのですが、これまでWindowsのGUIインストーラーをダブルクリックするだけの世界に育ってきたので苦戦しました。
パッケージ管理システムを使ってインストールするのが簡単なことは分かったのですが、なんと、そのパッケージ管理システムが何種類もあります。今の私のUbuntu 16.04 LTS ＋ Python 3.5.2 :: Anaconda 4.1.1 (64-bit)という環境では、次の3つの選択肢があるようです。

| システム | 概要 | | 参考にさせていただいたサイト |
|--------|--------|--------|----|
|conda|Anacondaに含まれるパッケージ管理システム|[問題02](http://qiita.com/segavvy/items/725b20f21951975a06fd)に取り組む際に、面倒なパッケージ管理を簡単にするためにAnacondaをインストールしましたので、これを使うのがベストのようです。|[Anaconda で Python 環境をインストールする](http://qiita.com/t2y/items/2a3eb58103e85d8064b6)|
|pip|Pythonのパッケージ管理システム|Pythonに関連するものは、これを使うのが良さそうです。|[Pythonのパッケージ管理システムpipのインストールと使い方](http://uxmilk.jp/12691)|
|apt|Ubuntuのパッケージ管理システム|Linuxで一般的なパッケージ管理システムのようです。condaやpipで入れられないものは、これを使うことになりそうです。|[Ubuntu 16.04 / Debian 8: aptコマンドの使い方](http://www.hiroom2.com/2016/05/12/ubuntu-16-04-debian-8のaptコマンドの使い方/)|

他にも`apt-get`を使うとか、ソース落としてきて`make`しましょうとか手順はいろいろあるみたいですが、深追いするとMeCabにたどり着く前に心が折れそうなので、簡単にできそうなもので前に進みます。初学者にとっては、この辺を適当に割り切ってモチベーションを維持することも大切です^^

###MeCabのインストール

今回の問題で必要になるパッケージは次の4つです。

| 必要なパッケージ | 概要 | オフィシャルサイト |
|--------|--------|-----|
|mecab| オープンソースの形態素解析エンジンです。正式名はMeCab (和布蕪)です。|[MeCab: Yet Another Part-of-Speech and Morphological Analyzer](http://taku910.github.io/mecab/)|
|mecab-naist-jdic|MeCabで必要な辞書データです。使える一般的な辞書は何種類かあるのですが、現在はこれが推奨されているようです。|[NAIST Japanese Dictionary](https://ja.osdn.net/projects/naist-jdic/)|
|libmecab-dev|MeCabを自分のプログラムに組み込む時に必要になるライブラリやヘッダーファイル、関連コマンドの詰め合わせです。次のmecab-python3をインストールする際に必要です。|[パッケージ: libmecab-dev (0.996-1.2ubuntu1) [universe]](http://packages.ubuntu.com/ja/xenial/libmecab-dev)|
|mecab-python3|MeCabをPython3で使うためのライブラリです。|[mecab-python3 0.7](https://pypi.python.org/pypi/mecab-python3)|

このそれぞれを、`conda`、`pip`、`apt`の順で探して、最初に見つかったパッケージ管理システムでインストールします。

####パッケージ管理システムでの検索
必要なパケージは全て名前にmecabが付くので、それぞれのパッケージ管理システムをmecabで検索してみます。

```console:端末（condaでmecabを検索）
segavvy@ubuntu:~$ conda search mecab
Fetching package metadata .......
```

`conda`にはありませんでした。

```console:端末（pipでmecabを検索）
segavvy@ubuntu:~$ pip search mecab
neologdn (0.2)               - Japanese text normalizer for mecab-neologd
c2.splitter.mecabja (1.0b2)  - This product is Japanese splitter by Mecab for
                               Plone
mecab-python (0.993)         - UNKNOWN
natto-py (0.8.0)             - A Tasty Python Binding with MeCab(FFI-based, no
                               SWIG or compiler necessary)
mecab-python3 (0.7)          - python wrapper for mecab: Morphological
                               Analysis engine
```

`pip`でmecab-python3を発見！

```console:端末（aptでmecabを検索）
segavvy@ubuntu:~$ apt search mecab
ソート中... 完了
全文検索... 完了  
darts/xenial 0.32-14 amd64
  C++ Template Library for implementation of Double-Array

groonga-tokenizer-mecab/xenial 6.0.1-1ubuntu1 amd64
  MeCab tokenizer for Groonga

libmecab-dev/xenial 0.996-1.2ubuntu1 amd64
  Header files of Mecab

libmecab-java/xenial,xenial 0.99.6-1build2 all
  Java 用 mecab バインディング - java クラス

libmecab-jni/xenial 0.99.6-1build2 amd64
  mecab binding for Java - native interface

libmecab-perl/xenial 0.99.6-1build4 amd64
  mecab binding for Perl

libmecab2/xenial 0.996-1.2ubuntu1 amd64
  Libraries of Mecab

libtext-mecab-perl/xenial 0.20016-1build4 amd64
  alternate MeCab Interface for Perl

mecab/xenial 0.996-1.2ubuntu1 amd64
  日本語形態素解析システム

mecab-ipadic/xenial,xenial 2.7.0-20070801+main-1 all
  IPA dictionary compiled for Mecab

mecab-ipadic-utf8/xenial,xenial 2.7.0-20070801+main-1 all
  IPA dictionary encoded in UTF-8 compiled for Mecab

mecab-jumandic/xenial,xenial 5.1+20070304-3 all
  Juman dictionary compiled for Mecab

mecab-jumandic-utf8/xenial,xenial 5.1+20070304-3 all
  Juman dictionary encoded in UTF-8 compiled for Mecab

mecab-naist-jdic/xenial,xenial 0.6.3.b-20111013-7 all
  free Japanese Dictionaries for mecab (replacement of mecab-ipadic)

mecab-naist-jdic-eucjp/xenial,xenial 0.6.3.b-20111013-7 all
  free Japanese Dictionaries for mecab (replacement of mecab-ipadic) in EUC-JP

mecab-utils/xenial 0.996-1.2ubuntu1 amd64
  Mecab のサポートプログラム

open-jtalk/xenial 1.07-2 amd64
  Japanese text-to-speech system

open-jtalk-mecab-naist-jdic/xenial,xenial 1.07-2 all
  NAIST Japanese Dictionary for Open JTalk

python-mecab/xenial 0.99.6-1build2 amd64
  mecab binding for Python

ruby-mecab/xenial 0.99.6-2build7 amd64
  mecab binding for Ruby language

unidic-mecab/xenial,xenial 2.1.2~dfsg-6 all
  free Japanese Dictionaries for mecab
```

mecabとmecab-naist-jdicとlibmecab-devは`apt`にありました。

####MeCab本体のインストール
まずmecabを`apt`でインストールしました。

```console:端末（mecabインストール）
segavvy@ubuntu:~$ sudo apt install mecab
[sudo] segavvy のパスワード: 
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
以下のパッケージが自動でインストールされましたが、もう必要とされていません:
  libpango1.0-0 libpangox-1.0-0 linux-headers-4.4.0-21
  linux-headers-4.4.0-21-generic linux-headers-4.4.0-36
  linux-headers-4.4.0-36-generic linux-headers-4.4.0-38
  linux-headers-4.4.0-38-generic linux-image-4.4.0-21-generic
  linux-image-4.4.0-36-generic linux-image-4.4.0-38-generic
  linux-image-extra-4.4.0-21-generic linux-image-extra-4.4.0-36-generic
  linux-image-extra-4.4.0-38-generic
これを削除するには 'sudo apt autoremove' を利用してください。
以下の追加パッケージがインストールされます:
  libmecab2 mecab-jumandic mecab-utils
以下のパッケージが新たにインストールされます:
  libmecab2 mecab mecab-jumandic mecab-utils
アップグレード: 0 個、新規インストール: 4 個、削除: 0 個、保留: 84 個。
13.3 MB のアーカイブを取得する必要があります。
この操作後に追加で 81.4 MB のディスク容量が消費されます。
続行しますか? [Y/n] y
取得:1 http://us.archive.ubuntu.com/ubuntu xenial/universe amd64 libmecab2 amd64 0.996-1.2ubuntu1 [264 kB]
取得:2 http://us.archive.ubuntu.com/ubuntu xenial/universe amd64 mecab-utils amd64 0.996-1.2ubuntu1 [4,566 B]
取得:3 http://us.archive.ubuntu.com/ubuntu xenial/universe amd64 mecab-jumandic all 5.1+20070304-3 [13.0 MB]
取得:4 http://us.archive.ubuntu.com/ubuntu xenial/universe amd64 mecab amd64 0.996-1.2ubuntu1 [83.2 kB]
13.3 MB を 10秒 で取得しました (1,223 kB/s)                                    
以前に未選択のパッケージ libmecab2 を選択しています。
(データベースを読み込んでいます ... 現在 305486 個のファイルとディレクトリがインストールされています。)
.../libmecab2_0.996-1.2ubuntu1_amd64.deb を展開する準備をしています ...
libmecab2 (0.996-1.2ubuntu1) を展開しています...
以前に未選択のパッケージ mecab-utils を選択しています。
.../mecab-utils_0.996-1.2ubuntu1_amd64.deb を展開する準備をしています ...
mecab-utils (0.996-1.2ubuntu1) を展開しています...
以前に未選択のパッケージ mecab-jumandic を選択しています。
.../mecab-jumandic_5.1+20070304-3_all.deb を展開する準備をしています ...
mecab-jumandic (5.1+20070304-3) を展開しています...
以前に未選択のパッケージ mecab を選択しています。
.../mecab_0.996-1.2ubuntu1_amd64.deb を展開する準備をしています ...
mecab (0.996-1.2ubuntu1) を展開しています...
libc-bin (2.23-0ubuntu3) のトリガを処理しています ...
man-db (2.7.5-1) のトリガを処理しています ...
libmecab2 (0.996-1.2ubuntu1) を設定しています ...
mecab-utils (0.996-1.2ubuntu1) を設定しています ...
mecab-jumandic (5.1+20070304-3) を設定しています ...
Compiling Juman dictionary for Mecab.  This takes long time...
reading /usr/share/mecab/dic/juman/unk.def ... 37
emitting double-array: 100% |###########################################| 
/usr/share/mecab/dic/juman/model.def is not found. skipped.
reading /usr/share/mecab/dic/juman/ContentW.csv ... 483161
reading /usr/share/mecab/dic/juman/Demonstrative.csv ... 76
reading /usr/share/mecab/dic/juman/Postp.csv ... 104
reading /usr/share/mecab/dic/juman/Prefix.csv ... 75
reading /usr/share/mecab/dic/juman/AuxV.csv ... 421
reading /usr/share/mecab/dic/juman/Noun.keishiki.csv ... 10
reading /usr/share/mecab/dic/juman/Noun.koyuu.csv ... 29805
reading /usr/share/mecab/dic/juman/Noun.suusi.csv ... 46
reading /usr/share/mecab/dic/juman/Noun.hukusi.csv ... 74
reading /usr/share/mecab/dic/juman/Special.csv ... 124
reading /usr/share/mecab/dic/juman/Assert.csv ... 30
reading /usr/share/mecab/dic/juman/Rengo.csv ... 913
reading /usr/share/mecab/dic/juman/Suffix.csv ... 1163
emitting double-array: 100% |###########################################| 
reading /usr/share/mecab/dic/juman/matrix.def ... 1509x1509
emitting matrix      : 100% |###########################################| 

done!
update-alternatives: /var/lib/mecab/dic/debian (mecab-dictionary) を提供するために自動モードで /var/lib/mecab/dic/juman を使います
mecab (0.996-1.2ubuntu1) を設定しています ...
Compiling Juman dictionary for Mecab.  This takes long time...
reading /usr/share/mecab/dic/juman/unk.def ... 37
emitting double-array: 100% |###########################################| 
/usr/share/mecab/dic/juman/model.def is not found. skipped.
reading /usr/share/mecab/dic/juman/ContentW.csv ... 483161
reading /usr/share/mecab/dic/juman/Demonstrative.csv ... 76
reading /usr/share/mecab/dic/juman/Postp.csv ... 104
reading /usr/share/mecab/dic/juman/Prefix.csv ... 75
reading /usr/share/mecab/dic/juman/AuxV.csv ... 421
reading /usr/share/mecab/dic/juman/Noun.keishiki.csv ... 10
reading /usr/share/mecab/dic/juman/Noun.koyuu.csv ... 29805
reading /usr/share/mecab/dic/juman/Noun.suusi.csv ... 46
reading /usr/share/mecab/dic/juman/Noun.hukusi.csv ... 74
reading /usr/share/mecab/dic/juman/Special.csv ... 124
reading /usr/share/mecab/dic/juman/Assert.csv ... 30
reading /usr/share/mecab/dic/juman/Rengo.csv ... 913
reading /usr/share/mecab/dic/juman/Suffix.csv ... 1163
emitting double-array: 100% |###########################################| 
reading /usr/share/mecab/dic/juman/matrix.def ... 1509x1509
emitting matrix      : 100% |###########################################| 

done!
libc-bin (2.23-0ubuntu3) のトリガを処理しています ...
```

何かいろいろメッセージは出ていますが、致命的なものはなさそうです。

####mecab-naist-jdicのインストール
続いてmecab-naist-jdicです。これも`apt`でインストールしました。

```console:端末（mecab-naist-jdicインストール）
segavvy@ubuntu:~$ sudo apt install mecab-naist-jdic
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
以下のパッケージが自動でインストールされましたが、もう必要とされていません:
  libpango1.0-0 libpangox-1.0-0 linux-headers-4.4.0-21
  linux-headers-4.4.0-21-generic linux-headers-4.4.0-36
  linux-headers-4.4.0-36-generic linux-headers-4.4.0-38
  linux-headers-4.4.0-38-generic linux-image-4.4.0-21-generic
  linux-image-4.4.0-36-generic linux-image-4.4.0-38-generic
  linux-image-extra-4.4.0-21-generic linux-image-extra-4.4.0-36-generic
  linux-image-extra-4.4.0-38-generic
これを削除するには 'sudo apt autoremove' を利用してください。
以下の追加パッケージがインストールされます:
  mecab-naist-jdic-eucjp
以下のパッケージが新たにインストールされます:
  mecab-naist-jdic mecab-naist-jdic-eucjp
アップグレード: 0 個、新規インストール: 2 個、削除: 0 個、保留: 84 個。
17.9 MB のアーカイブを取得する必要があります。
この操作後に追加で 152 MB のディスク容量が消費されます。
続行しますか? [Y/n] y
取得:1 http://us.archive.ubuntu.com/ubuntu xenial/universe amd64 mecab-naist-jdic-eucjp all 0.6.3.b-20111013-7 [17.9 MB]
取得:2 http://us.archive.ubuntu.com/ubuntu xenial/universe amd64 mecab-naist-jdic all 0.6.3.b-20111013-7 [3,170 B]
17.9 MB を 10秒 で取得しました (1,734 kB/s)                                    
以前に未選択のパッケージ mecab-naist-jdic-eucjp を選択しています。
(データベースを読み込んでいます ... 現在 305563 個のファイルとディレクトリがインストールされています。)
.../mecab-naist-jdic-eucjp_0.6.3.b-20111013-7_all.deb を展開する準備をしています ...
mecab-naist-jdic-eucjp (0.6.3.b-20111013-7) を展開しています...
以前に未選択のパッケージ mecab-naist-jdic を選択しています。
.../mecab-naist-jdic_0.6.3.b-20111013-7_all.deb を展開する準備をしています ...
mecab-naist-jdic (0.6.3.b-20111013-7) を展開しています...
mecab-naist-jdic-eucjp (0.6.3.b-20111013-7) を設定しています ...
Now generating naist-jdic data for Mecab. This may take a while...
reading /usr/share/mecab/dic/naist-jdic-eucjp/unk.def ... 40
emitting double-array: 100% |###########################################| 
/usr/share/mecab/dic/naist-jdic-eucjp/model.def is not found. skipped.
reading /usr/share/mecab/dic/naist-jdic-eucjp/naist-jdic.csv ... 485863
emitting double-array: 100% |###########################################| 
reading /usr/share/mecab/dic/naist-jdic-eucjp/matrix.def ... 1396x1396
emitting matrix      : 100% |###########################################| 

done!
Check /var/lib/mecab/dic/naist-jdic-eucjp directory.
update-alternatives: /var/lib/mecab/dic/debian (mecab-dictionary) を提供するために自動モードで /var/lib/mecab/dic/naist-jdic-eucjp を使います
mecab-naist-jdic (0.6.3.b-20111013-7) を設定しています ...
Now generating naist-jdic data for Mecab. This may take a while...
reading /usr/share/mecab/dic/naist-jdic-eucjp/unk.def ... 40
emitting double-array: 100% |###########################################| 
/usr/share/mecab/dic/naist-jdic-eucjp/model.def is not found. skipped.
reading /usr/share/mecab/dic/naist-jdic-eucjp/naist-jdic.csv ... 485863
emitting double-array: 100% |###########################################| 
reading /usr/share/mecab/dic/naist-jdic-eucjp/matrix.def ... 1396x1396
emitting matrix      : 100% |###########################################| 

done!
Check /var/lib/mecab/dic/naist-jdic directory.
update-alternatives: /var/lib/mecab/dic/debian (mecab-dictionary) を提供するために自動モードで /var/lib/mecab/dic/naist-jdic を使います
```

これも大丈夫そうです。
ここまででMeCabが使えるようになるはずなので、試してみました。`mecab`を実行して、適当に文章を入れると形態素解析してくれます。

```console:端末（MeCabを試す）
segavvy@ubuntu:~$ mecab
今日は良い天気です。
今日	名詞,副詞可能,*,*,*,*,今日,キョウ,キョー,,
は	助詞,係助詞,*,*,*,*,は,ハ,ワ,,
良い	形容詞,自立,*,*,形容詞・アウオ段,基本形,良い,ヨイ,ヨイ,よい/良い,
天気	名詞,一般,*,*,*,*,天気,テンキ,テンキ,,
です	助動詞,*,*,*,特殊・デス,基本形,です,デス,デス,,
。	記号,句点,*,*,*,*,。,。,。,,
EOS
^C
```

おぉ、すばらしい！

####libmecab-devのインストール

libmecab-devも`apt`でインストールします。

```console:端末（libmecab-devインストール）
segavvy@ubuntu:~$ sudo apt install libmecab-dev
[sudo] segavvy のパスワード: 
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
以下のパッケージが自動でインストールされましたが、もう必要とされていません:
  libpango1.0-0 libpangox-1.0-0 linux-headers-4.4.0-21
  linux-headers-4.4.0-21-generic linux-headers-4.4.0-36
  linux-headers-4.4.0-36-generic linux-headers-4.4.0-38
  linux-headers-4.4.0-38-generic linux-image-4.4.0-21-generic
  linux-image-4.4.0-36-generic linux-image-4.4.0-38-generic
  linux-image-extra-4.4.0-21-generic linux-image-extra-4.4.0-36-generic
  linux-image-extra-4.4.0-38-generic
これを削除するには 'sudo apt autoremove' を利用してください。
以下のパッケージが新たにインストールされます:
  libmecab-dev
アップグレード: 0 個、新規インストール: 1 個、削除: 0 個、保留: 84 個。
313 kB のアーカイブを取得する必要があります。
この操作後に追加で 3,261 kB のディスク容量が消費されます。
取得:1 http://us.archive.ubuntu.com/ubuntu xenial/universe amd64 libmecab-dev amd64 0.996-1.2ubuntu1 [313 kB]
313 kB を 2秒 で取得しました (141 kB/s)
以前に未選択のパッケージ libmecab-dev を選択しています。
(データベースを読み込んでいます ... 現在 305586 個のファイルとディレクトリがインストールされています。)
.../libmecab-dev_0.996-1.2ubuntu1_amd64.deb を展開する準備をしています ...
libmecab-dev (0.996-1.2ubuntu1) を展開しています...
man-db (2.7.5-1) のトリガを処理しています ...
libmecab-dev (0.996-1.2ubuntu1) を設定しています ...
```

これも問題なさそうです。

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

最後にmecab-python3です。これは`pip`でインストールしました。

```console:端末（mecab-python3のインストール）
segavvy@ubuntu:~$ pip install mecab-python3
Collecting mecab-python3
  Using cached mecab-python3-0.7.tar.gz
Building wheels for collected packages: mecab-python3
  Running setup.py bdist_wheel for mecab-python3 ... done
  Stored in directory: /home/segavvy/.cache/pip/wheels/6f/0e/eb/962d0d0c1ed7e2e03b9ff2ed186ab3034053b0e970cd04005c
Successfully built mecab-python3
Installing collected packages: mecab-python3
Successfully installed mecab-python3-0.7
```

これで、pythonで`import MeCab`できるようになるはずです。

```console:端末（MeCabのimport確認）
segavvy@ubuntu:~$ python
Python 3.5.2 |Anaconda 4.1.1 (64-bit)| (default, Jul  2 2016, 17:53:06) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import MeCab
>>> 
```

できました！
これで環境構築は完了です。ふぅ。
続いてプログラムのお話です。

###MeCabの使い方
MeCabの使い方そのものはネットに解説が豊富にあるので割愛します。

最初は1文ずつ解析させようとしていたのですが解析速度が驚くほど早く、私の環境では「吾輩は猫である」一冊を1,2秒で解析してしまうので、一気に読み込んで一気に`parse()`させています。

形態素解析結果のフォーマットは、本家の[MeCab: Yet Another Part-of-Speech and Morphological Analyzer](http://taku910.github.io/mecab/)に説明があり、

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

という形がデフォルトのようです。ただ、フォーマットはかなり自由に変えられるみたいで、今回のneko.txt.mecabの結果もすでに少し違っていて、発音の後ろに2カラムついていました。ただ今回の問題には関係しないようなので、気づかなかったことにしています。

###1文の境界の判定
文の終わりの判定に悩みました。どうすれば良いのかわからないので、今回は苦肉の策として品詞細分類1が`句点`のものを終わりと判定しています。
しかしこれだと、いきなり先頭の

>一
>
>　吾輩は猫である。
>名前はまだ無い。

の部分で「一」を1文とは判定せず、「一　吾輩は猫である。」までを1文だと誤判定してしまいます。うーん、イマイチ。neko.txt.mecabを作る段階で、何か改行が分かるようなマークを出力しておけば良いのかも知れません。

###ジェネレータ
今回初めて[ジェネレータ](http://docs.python.jp/3/glossary.html#term-generator)を使いました。
neko.txt.mecabから必要な行だけを読み込んで順次処理する形にしたかったため、最初はイテレータのクラスを作ろうとしていたのですが、調べていくとジェネレータにすればクラス化するまでもなく関数1つで実現できることがわかり、今回の実装になりました。
関数内で`return`の代わりに[`yield`](http://docs.python.jp/3/reference/expressions.html#yield-expressions)を使うと、次の呼び出し時にそこから再開される仕組みです。これは便利！

　
31本目のノックは以上です。誤りなどありましたら、ご指摘いただけますと幸いです。
<hr>

*実行結果には、[100本ノックで用いるコーパス・データ](http://www.cl.ecei.tohoku.ac.jp/nlp100/#data)で配布されているデータの一部が含まれます。この第4章で用いているデータは[青空文庫](http://www.aozora.gr.jp)で公開されている夏目漱石の長編小説『吾輩は猫である』が元になっています。*