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


[言語処理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)からどうぞ。

## 第5章: 係り受け解析
>夏目漱石の小説『吾輩は猫である』の文章（neko.txt）をCaboChaを使って係り受け解析し，その結果をneko.txt.cabochaというファイルに保存せよ．このファイルを用いて，以下の問に対応するプログラムを実装せよ．

###40. 係り受け解析結果の読み込み（形態素）
>形態素を表すクラスMorphを実装せよ．このクラスは表層形（surface），基本形（base），品詞（pos），品詞細分類1（pos1）をメンバ変数に持つこととする．さらに，CaboChaの解析結果（neko.txt.cabocha）を読み込み，各文をMorphオブジェクトのリストとして表現し，3文目の形態素列を表示せよ．

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

```python:main.py
# coding: utf-8
import CaboCha

fname = 'neko.txt'
fname_parsed = 'neko.txt.cabocha'


def parse_neko():
	'''「吾輩は猫である」を係り受け解析
	「吾輩は猫である」(neko.txt)を係り受け解析してneko.txt.cabochaに保存する
	'''
	with open(fname) as data_file, \
			open(fname_parsed, mode='w') as out_file:

		cabocha = CaboCha.Parser()
		for line in data_file:
			out_file.write(
				cabocha.parse(line).toString(CaboCha.FORMAT_LATTICE)
			)


class Morph:
	'''
	形態素クラス
	表層形（surface）、基本形（base）、品詞（pos）、品詞細分類1（pos1）を
	メンバー変数に持つ
	'''
	def __init__(self, surface, base, pos, pos1):
		'''初期化'''
		self.surface = surface
		self.base = base
		self.pos = pos
		self.pos1 = pos1

	def __str__(self):
		'''オブジェクトの文字列表現'''
		return 'surface[{}]\tbase[{}]\tpos[{}]\tpos1[{}]'\
			.format(self.surface, self.base, self.pos, self.pos1)


def neco_lines():
	'''「吾輩は猫である」の係り受け解析結果のジェネレータ
	「吾輩は猫である」の係り受け解析結果を順次読み込んで、
	1文ずつMorphクラスのリストを返す

	戻り値：
	1文のMorphクラスのリスト
	'''
	with open(fname_parsed) as file_parsed:

		morphs = []
		for line in file_parsed:

			# 1文の終了判定
			if line == 'EOS\n':
				yield morphs
				morphs = []

			else:
				# 先頭が*の行は係り受け解析結果なのでスキップ
				if line[0] == '*':
					continue

				# 表層形はtab区切り、それ以外は','区切りでバラす
				cols = line.split('\t')
				res_cols = cols[1].split(',')

				# Morph作成、リストに追加
				morphs.append(Morph(
					cols[0],		# surface
					res_cols[6],	# base
					res_cols[0],	# pos
					res_cols[1]		# pos1
				))

		raise StopIteration


# 係り受け解析
parse_neko()

# 1文ずつリスト作成
for i, morphs in enumerate(neco_lines(), 1):

	# 3文目を表示
	if i == 3:
		for morph in morphs:
			print(morph)
		break
```

####実行結果：

今回のプログラムの実行結果です。

```console:端末
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[句点]
```

なお、係り受け解析結果neko.txt.cabochaの中身については後述します。


###CaboChaのインストール

まず、問題に取り組む前に環境構築です。
追加で必要になるパッケージは次の3つです。なお、MeCabも必要ですが、[問題30](http://qiita.com/segavvy/items/1f517e06aa3bc5fc2316)でインストール済みなのでここでは割愛します。

| 必要なパッケージ | 概要 | オフィシャルサイト |
|--------|--------|-----|
|CRF++| CaboChaで必要になるオープンソースのCRFライブラリです。CRFは形態素解析でよく使われるアルゴリズムだそうです。|[CRF++: Yet Another CRF toolkit](https://taku910.github.io/crfpp/)|
|mecab-ipadic|CaboChaで必要になる辞書データで、mecab-ipadic, mecab-jumandic, unidicのいずれかが必要です（[問題30](http://qiita.com/segavvy/items/1f517e06aa3bc5fc2316)でMeCabを使うために入れたmecab-naist-jdicは残念ながら使えないみたいです）。今回はmecab-ipadicを入れました。|[IPAdic legacy](https://ja.osdn.net/projects/ipadic/)|
|CaboCha|南瓜です。Support Vector Machinesを使った日本語の係り受け解析器のフリーソフトで、Python3で使うためのライブラリも含まれています。なお、付属しているモデルファイルの利用は研究目的、個人利用に限られるので、商用利用する場合は注意が必要です。詳しくはオフィシャルサイトでご確認ください。|[CaboCha/南瓜: Yet Another Japanese Dependency Structure Analyzer](https://taku910.github.io/cabocha/)|

mecab-ipadicだけはaptでインストールできますが、それ以外はダウンロードしてきてmakeする必要があります。
以下に手順をまとめます。

####CRF++のインストール

まず[CRF++のオフィシャルサイトのDownloadの説明](https://taku910.github.io/crfpp/#download)にある[リンク](https://drive.google.com/folderview?id=0B4y35FiV1wh7fngteFhHQUN2Y1B5eUJBNHZUemJYQV9VWlBUb3JlX0xBdWVZTWtSbVBneU0&usp=drive_web#list)から、`CRF++-0.58.tar.gz`（ソース一式）をダウンロードします。現時点では0.58が最新でした。

![Kobito.3yGrCN.png](https://qiita-image-store.s3.amazonaws.com/0/139624/36934da9-cb01-0fc4-42da-33e761758ef9.png "Kobito.3yGrCN.png")

私はファイルをホームにおいて`tar`で解凍しました。`tar`は、だいたいどんなファイルでも`axvf`を指定すれば拡張子で適当に判断して解凍してくれるそうです。便利^^

```console:端末（CRF++-0.58.tar.gzの解凍、先頭部分）
segavvy@ubuntu:~$ tar axvf CRF++-0.58.tar.gz
CRF++-0.58/
CRF++-0.58/INSTALL
CRF++-0.58/python/
CRF++-0.58/python/test.py
CRF++-0.58/python/README
（以下略）
```

解凍したディレクトリに移動して`configure`します。これは環境に合わせてインストールに必要なものを最適化するためのスクリプトだそうです。

```console:端末（configure、先頭部分）
segavvy@ubuntu:~/CRF++-0.58$ ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... no
checking for mawk... mawk
(以下略)
```

そして`sudo make install`でインストールします。

```console:端末（make）
segavvy@ubuntu:~/CRF++-0.58$ sudo make install
[sudo] segavvy のパスワード: 
/bin/bash ./libtool --tag=CXX   --mode=compile g++ -DHAVE_CONFIG_H -I.     -O3 -Wall -c -o libcrfpp.lo libcrfpp.cpp
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c libcrfpp.cpp  -fPIC -DPIC -o .libs/libcrfpp.o
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c libcrfpp.cpp -o libcrfpp.o >/dev/null 2>&1
/bin/bash ./libtool --tag=CXX   --mode=compile g++ -DHAVE_CONFIG_H -I.     -O3 -Wall -c -o lbfgs.lo lbfgs.cpp
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c lbfgs.cpp  -fPIC -DPIC -o .libs/lbfgs.o
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c lbfgs.cpp -o lbfgs.o >/dev/null 2>&1
/bin/bash ./libtool --tag=CXX   --mode=compile g++ -DHAVE_CONFIG_H -I.     -O3 -Wall -c -o param.lo param.cpp
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c param.cpp  -fPIC -DPIC -o .libs/param.o
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c param.cpp -o param.o >/dev/null 2>&1
/bin/bash ./libtool --tag=CXX   --mode=compile g++ -DHAVE_CONFIG_H -I.     -O3 -Wall -c -o encoder.lo encoder.cpp
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c encoder.cpp  -fPIC -DPIC -o .libs/encoder.o
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c encoder.cpp -o encoder.o >/dev/null 2>&1
/bin/bash ./libtool --tag=CXX   --mode=compile g++ -DHAVE_CONFIG_H -I.     -O3 -Wall -c -o feature.lo feature.cpp
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c feature.cpp  -fPIC -DPIC -o .libs/feature.o
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c feature.cpp -o feature.o >/dev/null 2>&1
/bin/bash ./libtool --tag=CXX   --mode=compile g++ -DHAVE_CONFIG_H -I.     -O3 -Wall -c -o feature_cache.lo feature_cache.cpp
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c feature_cache.cpp  -fPIC -DPIC -o .libs/feature_cache.o
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c feature_cache.cpp -o feature_cache.o >/dev/null 2>&1
/bin/bash ./libtool --tag=CXX   --mode=compile g++ -DHAVE_CONFIG_H -I.     -O3 -Wall -c -o feature_index.lo feature_index.cpp
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c feature_index.cpp  -fPIC -DPIC -o .libs/feature_index.o
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c feature_index.cpp -o feature_index.o >/dev/null 2>&1
/bin/bash ./libtool --tag=CXX   --mode=compile g++ -DHAVE_CONFIG_H -I.     -O3 -Wall -c -o node.lo node.cpp
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c node.cpp  -fPIC -DPIC -o .libs/node.o
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c node.cpp -o node.o >/dev/null 2>&1
/bin/bash ./libtool --tag=CXX   --mode=compile g++ -DHAVE_CONFIG_H -I.     -O3 -Wall -c -o path.lo path.cpp
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c path.cpp  -fPIC -DPIC -o .libs/path.o
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c path.cpp -o path.o >/dev/null 2>&1
/bin/bash ./libtool --tag=CXX   --mode=compile g++ -DHAVE_CONFIG_H -I.     -O3 -Wall -c -o tagger.lo tagger.cpp
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c tagger.cpp  -fPIC -DPIC -o .libs/tagger.o
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -O3 -Wall -c tagger.cpp -o tagger.o >/dev/null 2>&1
/bin/bash ./libtool --tag=CXX   --mode=link g++  -O3 -Wall   -o libcrfpp.la -rpath /usr/local/lib libcrfpp.lo lbfgs.lo param.lo encoder.lo feature.lo feature_cache.lo feature_index.lo node.lo path.lo tagger.lo  -lpthread -lpthread -lm -lm -lm 
libtool: link: g++  -fPIC -DPIC -shared -nostdlib /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/5/crtbeginS.o  .libs/libcrfpp.o .libs/lbfgs.o .libs/param.o .libs/encoder.o .libs/feature.o .libs/feature_cache.o .libs/feature_index.o .libs/node.o .libs/path.o .libs/tagger.o   -lpthread -L/usr/lib/gcc/x86_64-linux-gnu/5 -L/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/5/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/5/../../.. -lstdc++ -lm -lc -lgcc_s /usr/lib/gcc/x86_64-linux-gnu/5/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crtn.o  -O3   -Wl,-soname -Wl,libcrfpp.so.0 -o .libs/libcrfpp.so.0.0.0
libtool: link: (cd ".libs" && rm -f "libcrfpp.so.0" && ln -s "libcrfpp.so.0.0.0" "libcrfpp.so.0")
libtool: link: (cd ".libs" && rm -f "libcrfpp.so" && ln -s "libcrfpp.so.0.0.0" "libcrfpp.so")
libtool: link: ar cru .libs/libcrfpp.a  libcrfpp.o lbfgs.o param.o encoder.o feature.o feature_cache.o feature_index.o node.o path.o tagger.o
ar: `u' modifier ignored since `D' is the default (see `U')
libtool: link: ranlib .libs/libcrfpp.a
libtool: link: ( cd ".libs" && rm -f "libcrfpp.la" && ln -s "../libcrfpp.la" "libcrfpp.la" )
g++ -DHAVE_CONFIG_H -I.     -O3 -Wall -c -o crf_learn.o crf_learn.cpp
/bin/bash ./libtool --tag=CXX   --mode=link g++  -O3 -Wall   -o crf_learn crf_learn.o libcrfpp.la -lpthread -lpthread -lm -lm -lm 
libtool: link: g++ -O3 -Wall -o .libs/crf_learn crf_learn.o  ./.libs/libcrfpp.so -lpthread -lm
g++ -DHAVE_CONFIG_H -I.     -O3 -Wall -c -o crf_test.o crf_test.cpp
/bin/bash ./libtool --tag=CXX   --mode=link g++  -O3 -Wall   -o crf_test crf_test.o libcrfpp.la  -lpthread -lpthread -lm -lm -lm 
libtool: link: g++ -O3 -Wall -o .libs/crf_test crf_test.o  ./.libs/libcrfpp.so -lpthread -lm
make[1]: ディレクトリ '/home/segavvy/CRF++-0.58' に入ります
test -z "/usr/local/lib" || /bin/mkdir -p "/usr/local/lib"
 /bin/bash ./libtool   --mode=install /usr/bin/install -c   libcrfpp.la '/usr/local/lib'
libtool: install: /usr/bin/install -c .libs/libcrfpp.so.0.0.0 /usr/local/lib/libcrfpp.so.0.0.0
libtool: install: (cd /usr/local/lib && { ln -s -f libcrfpp.so.0.0.0 libcrfpp.so.0 || { rm -f libcrfpp.so.0 && ln -s libcrfpp.so.0.0.0 libcrfpp.so.0; }; })
libtool: install: (cd /usr/local/lib && { ln -s -f libcrfpp.so.0.0.0 libcrfpp.so || { rm -f libcrfpp.so && ln -s libcrfpp.so.0.0.0 libcrfpp.so; }; })
libtool: install: /usr/bin/install -c .libs/libcrfpp.lai /usr/local/lib/libcrfpp.la
libtool: install: /usr/bin/install -c .libs/libcrfpp.a /usr/local/lib/libcrfpp.a
libtool: install: chmod 644 /usr/local/lib/libcrfpp.a
libtool: install: ranlib /usr/local/lib/libcrfpp.a
libtool: finish: PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/sbin" ldconfig -n /usr/local/lib
----------------------------------------------------------------------
Libraries have been installed in:
   /usr/local/lib

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
     during execution
   - add LIBDIR to the `LD_RUN_PATH' environment variable
     during linking
   - use the `-Wl,-rpath -Wl,LIBDIR' linker flag
   - have your system administrator add LIBDIR to `/etc/ld.so.conf'

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
test -z "/usr/local/bin" || /bin/mkdir -p "/usr/local/bin"
  /bin/bash ./libtool   --mode=install /usr/bin/install -c crf_learn crf_test '/usr/local/bin'
libtool: install: /usr/bin/install -c .libs/crf_learn /usr/local/bin/crf_learn
libtool: install: /usr/bin/install -c .libs/crf_test /usr/local/bin/crf_test
test -z "/usr/local/include" || /bin/mkdir -p "/usr/local/include"
 /usr/bin/install -c -m 644 crfpp.h '/usr/local/include'
make[1]: ディレクトリ '/home/segavvy/CRF++-0.58' から出ます
```

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

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

続いてmecab-ipadicのインストールです。これはaptが使えるので簡単です。

```console:端末（インストール）
segavvy@ubuntu:~$ sudo apt install mecab-ipadic
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
以下のパッケージが自動でインストールされましたが、もう必要とされていません:
  linux-headers-4.4.0-42 linux-headers-4.4.0-42-generic
  linux-image-4.4.0-42-generic linux-image-extra-4.4.0-42-generic
これを削除するには 'sudo apt autoremove' を利用してください。
以下のパッケージが新たにインストールされます:
  mecab-ipadic
アップグレード: 0 個、新規インストール: 1 個、削除: 0 個、保留: 125 個。
12.1 MB のアーカイブを取得する必要があります。
この操作後に追加で 54.4 MB のディスク容量が消費されます。
取得:1 http://us.archive.ubuntu.com/ubuntu xenial/universe amd64 mecab-ipadic all 2.7.0-20070801+main-1 [12.1 MB]
12.1 MB を 56秒 で取得しました (214 kB/s)                                      
以前に未選択のパッケージ mecab-ipadic を選択しています。
(データベースを読み込んでいます ... 現在 241182 個のファイルとディレクトリがインストールされています。)
.../mecab-ipadic_2.7.0-20070801+main-1_all.deb を展開する準備をしています ...
mecab-ipadic (2.7.0-20070801+main-1) を展開しています...
mecab-ipadic (2.7.0-20070801+main-1) を設定しています ...
Compiling IPA dictionary for Mecab.  This takes long time...
reading /usr/share/mecab/dic/ipadic/unk.def ... 40
emitting double-array: 100% |###########################################| 
/usr/share/mecab/dic/ipadic/model.def is not found. skipped.
reading /usr/share/mecab/dic/ipadic/Adverb.csv ... 3032
reading /usr/share/mecab/dic/ipadic/Postp.csv ... 146
reading /usr/share/mecab/dic/ipadic/Noun.place.csv ... 72999
reading /usr/share/mecab/dic/ipadic/Noun.proper.csv ... 27327
reading /usr/share/mecab/dic/ipadic/Prefix.csv ... 221
reading /usr/share/mecab/dic/ipadic/Noun.adjv.csv ... 3328
reading /usr/share/mecab/dic/ipadic/Conjunction.csv ... 171
reading /usr/share/mecab/dic/ipadic/Noun.verbal.csv ... 12146
reading /usr/share/mecab/dic/ipadic/Adj.csv ... 27210
reading /usr/share/mecab/dic/ipadic/Noun.name.csv ... 34202
reading /usr/share/mecab/dic/ipadic/Postp-col.csv ... 91
reading /usr/share/mecab/dic/ipadic/Noun.adverbal.csv ... 795
reading /usr/share/mecab/dic/ipadic/Noun.nai.csv ... 42
reading /usr/share/mecab/dic/ipadic/Noun.demonst.csv ... 120
reading /usr/share/mecab/dic/ipadic/Adnominal.csv ... 135
reading /usr/share/mecab/dic/ipadic/Others.csv ... 2
reading /usr/share/mecab/dic/ipadic/Noun.number.csv ... 42
reading /usr/share/mecab/dic/ipadic/Filler.csv ... 19
reading /usr/share/mecab/dic/ipadic/Verb.csv ... 130750
reading /usr/share/mecab/dic/ipadic/Auxil.csv ... 199
reading /usr/share/mecab/dic/ipadic/Noun.others.csv ... 151
reading /usr/share/mecab/dic/ipadic/Suffix.csv ... 1393
reading /usr/share/mecab/dic/ipadic/Noun.org.csv ... 16668
reading /usr/share/mecab/dic/ipadic/Noun.csv ... 60477
reading /usr/share/mecab/dic/ipadic/Symbol.csv ... 208
reading /usr/share/mecab/dic/ipadic/Interjection.csv ... 252
emitting double-array: 100% |###########################################| 
reading /usr/share/mecab/dic/ipadic/matrix.def ... 1316x1316
emitting matrix      : 100% |###########################################| 

done!
```

これも致命的なものはなさそうです。

####CaboChaのインストール

次にCaboCha本体です。

[CaboChaのオフィシャルサイト](https://taku910.github.io/cabocha/)のダウンロードの説明にある[リンク](https://drive.google.com/folderview?id=0B4y35FiV1wh7cGRCUUJHVTNJRnM&usp=sharing#list)から、`cabocha-0.69.tar.bz2`（ソース一式）をダウンロードします。現時点では0.69が最新でした。

![Kobito.mBCjNl.png](https://qiita-image-store.s3.amazonaws.com/0/139624/59a2b6ee-c797-b6e2-9e3d-877f05dd54a2.png "Kobito.mBCjNl.png")

私はファイルをホームにおいて`tar`で解凍しました。

```console:端末（cabocha-0.69.tar.bz2の解凍、先頭部分）
segavvy@ubuntu:~$ tar axvf cabocha-0.69.tar.bz2
cabocha-0.69/
cabocha-0.69/cabocha-config.in
cabocha-0.69/compile
cabocha-0.69/swig/
cabocha-0.69/swig/version.h.in
(以下略)
```

次に解凍したディレクトリに移動して`configure`しますが、この時に1つ注意が必要です。

CaboChaはデフォルトの文字コードが日本語EUCなので、そのままmakeしてしまうとMeCabが使えません（これまでに使ってきたMeCabはUTF-8になっています）。そのため、`configure`で文字コードを指定しておく必要があります。

私はUTF-8以外で使うことがなさそうなため、[オフィシャルサイト](https://taku910.github.io/cabocha/)で解説されているUTF-8 only modeにするために、`./configure --with-charset=utf8 --enable-utf8-only`としてみました。

```console:端末（configure、先頭部分）
segavvy@ubuntu:~$ cd cabocha-0.69
segavvy@ubuntu:~/cabocha-0.69$ ./configure --with-charset=utf8 --enable-utf8-only
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... no
checking for mawk... mawk
checking whether make sets $(MAKE)... yes
(以下略)
```

インストール手順では次は`make`ですが、その前に`ldconfig`で共有ライブラリの依存関係の情報を更新しておく必要があります。更新しておかないと、先に入れたCRF++のライブラリを見つけてくれません。

この辺はLinuxを使う方にとっては常識のようで、オフィシャルサイトのインストール手順には書かれていないのが初学者には辛いところです。先にLinuxの入門書などで基礎を勉強しておかないとだめだったかな...

```console:端末（ldconfig）
segavvy@ubuntu:~/cabocha-0.69$ sudo ldconfig
```

そして`make`です。

```console:端末（make、先頭部分）
segavvy@ubuntu:~/cabocha-0.69$ make
make  all-recursive
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69' に入ります
Making all in src
make[2]: ディレクトリ '/home/segavvy/cabocha-0.69/src' に入ります
/bin/bash ../libtool  --tag=CXX   --mode=compile g++ -DHAVE_CONFIG_H -I. -I.. -DCABOCHA_DEFAULT_POSSET="\"IPA"\" -DCABOCHA_DEFAULT_CHARSET="\"UTF-8"\" -DMODEL_VERSION=102 -DCABOCHA_USE_UTF8_ONLY -DCABOCHA_DEFAULT_RC="\"/usr/local/etc/cabocharc\""    -O3 -Wno-deprecated -Wall -c -o chunk_learner.lo chunk_learner.cpp
libtool: compile:  g++ -DHAVE_CONFIG_H -I. -I.. -DCABOCHA_DEFAULT_POSSET=\"IPA\" -DCABOCHA_DEFAULT_CHARSET=\"UTF-8\" -DMODEL_VERSION=102 -DCABOCHA_USE_UTF8_ONLY -DCABOCHA_DEFAULT_RC=\"/usr/local/etc/cabocharc\" -O3 -Wno-deprecated -Wall -c chunk_learner.cpp  -fPIC -DPIC -o .libs/chunk_learner.o
```

（中略）

```console:端末（make、末尾）
Making all in model
make[2]: ディレクトリ '/home/segavvy/cabocha-0.69/model' に入ります
../src/cabocha-model-index -f UTF8 -t UTF-8 chunk.ipa.txt chunk.ipa.model
../src/cabocha-model-index -f UTF8 -t UTF-8 chunk.juman.txt chunk.juman.model
../src/cabocha-model-index -f UTF8 -t UTF-8 chunk.unidic.txt chunk.unidic.model
../src/cabocha-model-index -f UTF8 -t UTF-8 dep.ipa.txt dep.ipa.model
emitting dic    : 100% |###########################################| 
emitting trie   : 100% |###########################################| 

double array size : 2340864
trie         size : 22100992
feature size      : 122541
freq feature size : 3000
minsup            : 2
bias              : 113308
sigma             : 0.0001
normalize factor  : 1.98193e-07
Done!
21.72 s

../src/cabocha-model-index -f UTF8 -t UTF-8 dep.juman.txt dep.juman.model
emitting dic    : 100% |###########################################| 
emitting trie   : 100% |###########################################| 

double array size : 2892800
trie         size : 22047744
feature size      : 149674
freq feature size : 3000
minsup            : 2
bias              : 78200
sigma             : 0.0001
normalize factor  : 2.27711e-07
Done!
20.93 s

../src/cabocha-model-index -f UTF8 -t UTF-8 dep.unidic.txt dep.unidic.model
emitting dic    : 100% |###########################################| 
emitting trie   : 100% |###########################################| 

double array size : 2159616
trie         size : 19891200
feature size      : 121120
freq feature size : 3000
minsup            : 2
bias              : 92412
sigma             : 0.0001
normalize factor  : 2.27189e-07
Done!
20.13 s

../src/cabocha-model-index -f UTF8 -t UTF-8 ne.ipa.txt ne.ipa.model
../src/cabocha-model-index -f UTF8 -t UTF-8 ne.juman.txt ne.juman.model
../src/cabocha-model-index -f UTF8 -t UTF-8 ne.unidic.txt ne.unidic.model
make[2]: ディレクトリ '/home/segavvy/cabocha-0.69/model' から出ます
Making all in man
make[2]: ディレクトリ '/home/segavvy/cabocha-0.69/man' に入ります
make[2]: 'all' に対して行うべき事はありません.
make[2]: ディレクトリ '/home/segavvy/cabocha-0.69/man' から出ます
make[2]: ディレクトリ '/home/segavvy/cabocha-0.69' に入ります
make[2]: ディレクトリ '/home/segavvy/cabocha-0.69' から出ます
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69' から出ます
```

続いて`make check`。

```console:端末（check）
segavvy@ubuntu:~/cabocha-0.69$ make check
Making check in src
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69/src' に入ります
make[1]: 'check' に対して行うべき事はありません.
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69/src' から出ます
Making check in model
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69/model' に入ります
make[1]: 'check' に対して行うべき事はありません.
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69/model' から出ます
Making check in man
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69/man' に入ります
make[1]: 'check' に対して行うべき事はありません.
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69/man' から出ます
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69' に入ります
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69' から出ます
```

問題なさそうですね。
最後に`sudo make install`でインストールです。

```console:端末（install）
segavvy@ubuntu:~/cabocha-0.69$ sudo make install
Making install in src
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69/src' に入ります
make[2]: ディレクトリ '/home/segavvy/cabocha-0.69/src' に入ります
 /bin/mkdir -p '/usr/local/lib'
 /bin/bash ../libtool   --mode=install /usr/bin/install -c   libcabocha.la '/usr/local/lib'
libtool: install: /usr/bin/install -c .libs/libcabocha.so.5.0.0 /usr/local/lib/libcabocha.so.5.0.0
libtool: install: (cd /usr/local/lib && { ln -s -f libcabocha.so.5.0.0 libcabocha.so.5 || { rm -f libcabocha.so.5 && ln -s libcabocha.so.5.0.0 libcabocha.so.5; }; })
libtool: install: (cd /usr/local/lib && { ln -s -f libcabocha.so.5.0.0 libcabocha.so || { rm -f libcabocha.so && ln -s libcabocha.so.5.0.0 libcabocha.so; }; })
libtool: install: /usr/bin/install -c .libs/libcabocha.lai /usr/local/lib/libcabocha.la
libtool: install: /usr/bin/install -c .libs/libcabocha.a /usr/local/lib/libcabocha.a
libtool: install: chmod 644 /usr/local/lib/libcabocha.a
libtool: install: ranlib /usr/local/lib/libcabocha.a
libtool: finish: PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/sbin" ldconfig -n /usr/local/lib
----------------------------------------------------------------------
Libraries have been installed in:
   /usr/local/lib

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
     during execution
   - add LIBDIR to the `LD_RUN_PATH' environment variable
     during linking
   - use the `-Wl,-rpath -Wl,LIBDIR' linker flag
   - have your system administrator add LIBDIR to `/etc/ld.so.conf'

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
 /bin/mkdir -p '/usr/local/bin'
  /bin/bash ../libtool   --mode=install /usr/bin/install -c cabocha '/usr/local/bin'
libtool: install: /usr/bin/install -c .libs/cabocha /usr/local/bin/cabocha
 /bin/mkdir -p '/usr/local/libexec/cabocha'
  /bin/bash ../libtool   --mode=install /usr/bin/install -c cabocha-model-index cabocha-learn cabocha-system-eval '/usr/local/libexec/cabocha'
libtool: install: /usr/bin/install -c .libs/cabocha-model-index /usr/local/libexec/cabocha/cabocha-model-index
libtool: install: /usr/bin/install -c .libs/cabocha-learn /usr/local/libexec/cabocha/cabocha-learn
libtool: install: /usr/bin/install -c .libs/cabocha-system-eval /usr/local/libexec/cabocha/cabocha-system-eval
 /bin/mkdir -p '/usr/local/include'
 /usr/bin/install -c -m 644 cabocha.h '/usr/local/include'
make[2]: ディレクトリ '/home/segavvy/cabocha-0.69/src' から出ます
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69/src' から出ます
Making install in model
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69/model' に入ります
make[2]: ディレクトリ '/home/segavvy/cabocha-0.69/model' に入ります
make[2]: 'install-exec-am' に対して行うべき事はありません.
 /bin/mkdir -p '/usr/local/lib/cabocha/model'
 /usr/bin/install -c -m 644 chunk.ipa.model chunk.juman.model chunk.unidic.model dep.ipa.model dep.juman.model dep.unidic.model ne.ipa.model ne.juman.model ne.unidic.model '/usr/local/lib/cabocha/model'
make[2]: ディレクトリ '/home/segavvy/cabocha-0.69/model' から出ます
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69/model' から出ます
Making install in man
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69/man' に入ります
make[2]: ディレクトリ '/home/segavvy/cabocha-0.69/man' に入ります
make[2]: 'install-exec-am' に対して行うべき事はありません.
 /bin/mkdir -p '/usr/local/share/man/man1'
 /usr/bin/install -c -m 644 cabocha.1 '/usr/local/share/man/man1'
make[2]: ディレクトリ '/home/segavvy/cabocha-0.69/man' から出ます
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69/man' から出ます
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69' に入ります
make[2]: ディレクトリ '/home/segavvy/cabocha-0.69' に入ります
 /bin/mkdir -p '/usr/local/bin'
 /usr/bin/install -c cabocha-config '/usr/local/bin'
 /bin/mkdir -p '/usr/local/etc'
 /usr/bin/install -c -m 644 cabocharc '/usr/local/etc'
make[2]: ディレクトリ '/home/segavvy/cabocha-0.69' から出ます
make[1]: ディレクトリ '/home/segavvy/cabocha-0.69' から出ます
```

終わりました。これでCaboChaが使えるはず。

```console:端末
segavvy@ubuntu:~$ cabocha
cabocha: error while loading shared libraries: libcabocha.so.5: cannot open shared object file: No such file or directory
```

あれ、ライブラリが見つけられない...そっか、`ldconfig`だ。

```console:端末（ldconfig）
segavvy@ubuntu:~$ sudo ldconfig
segavvy@ubuntu:~$ cabocha
CaboChaのインストールもMeCabと同じくらい大変でした
     CaboChaの-D      
  インストールも-----D
           MeCabと-D |
          同じくらい-D
            大変でした
EOS
```

無事、CaboChaが動きました。

####CaboChaのPythonバインディングのインストール

最後にPythonでCaboChaを使うためのライブラリのインストールです。これはCaboChaに含まれていて、pythonディレクトリで`python setup.py install`すればOKです。

```console:端末（setup.py）
segavvy@ubuntu:~$ cd cabocha-0.69/python
segavvy@ubuntu:~/cabocha-0.69/python$ python setup.py install
running install
running build
running build_py
creating build
creating build/lib.linux-x86_64-3.5
copying CaboCha.py -> build/lib.linux-x86_64-3.5
running build_ext
building '_CaboCha' extension
creating build/temp.linux-x86_64-3.5
gcc -pthread -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/usr/local/include -I/home/segavvy/anaconda3/include/python3.5m -c CaboCha_wrap.cxx -o build/temp.linux-x86_64-3.5/CaboCha_wrap.o
cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++
warning: no library file corresponding to '-L/usr/lib' found (skipping)
g++ -pthread -shared -L/home/segavvy/anaconda3/lib -Wl,-rpath=/home/segavvy/anaconda3/lib,--no-as-needed build/temp.linux-x86_64-3.5/CaboCha_wrap.o -L/usr/local/lib -L/home/segavvy/anaconda3/lib -lcabocha -lcrfpp -lmecab -lmecab -lstdc++ -lpython3.5m -o build/lib.linux-x86_64-3.5/_CaboCha.cpython-35m-x86_64-linux-gnu.so
running install_lib
copying build/lib.linux-x86_64-3.5/_CaboCha.cpython-35m-x86_64-linux-gnu.so -> /home/segavvy/anaconda3/lib/python3.5/site-packages
copying build/lib.linux-x86_64-3.5/CaboCha.py -> /home/segavvy/anaconda3/lib/python3.5/site-packages
byte-compiling /home/segavvy/anaconda3/lib/python3.5/site-packages/CaboCha.py to CaboCha.cpython-35.pyc
running install_egg_info
Writing /home/segavvy/anaconda3/lib/python3.5/site-packages/cabocha_python-0.69-py3.5.egg-info
```

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

```console:端末（CaboChaの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 CaboCha
>>> 
```

できました！

環境構築はこれで完了です。
続いてプログラムのお話です。

###CaboChaの使い方
CaboChaの使い方そのものはネットに解説が豊富にあるので割愛します。Pythonでの使い方はcabocha-0.69/python/test.pyを見ると分かるかと思います。

CaboChaの解析結果のフォーマットは`CaboCha.FORMAT_LATTICE`を指定しました。この指定で、`cabocha -f1`で解析した時と同じフォーマットになります。このフォーマットはMeCabと似ているので、今回のコードはかなり[問題30](http://qiita.com/segavvy/items/1f517e06aa3bc5fc2316)に似ています。

以下、neko.txt.cabochaの先頭部分です。

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

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

###クラスの`__str__()`と`__repr__()`
今回初めてクラスを実装しましたが、オブジェクトを`print()`で表示できるように[`__str__()`](http://docs.python.jp/3/reference/datamodel.html#object.__str__)を実装してみました。
なお、オブジェクトを文字列化する関数には[`__repr__()`](http://docs.python.jp/3/reference/datamodel.html#object.__repr__)というのもあり、こちらは[`repr()`](http://docs.python.jp/3/library/functions.html#repr)で使われるそうです。[`__str__()`](http://docs.python.jp/3/reference/datamodel.html#object.__str__)はヒトに優しい表示向き、[`__repr__()`](http://docs.python.jp/3/reference/datamodel.html#object.__repr__)は開発者やプログラムに優しいPython式のようなもの、という使い分けだそうです。

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

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