Doc2Vecを使用するまでの環境構築手順

# はじめに
この記事は、CentOS 7.3でDoc2Vec(gensim)を使うまでの流れのメモです。
私が途中かなりハマったので、参考になれば幸いです。
だいぶ忘れてしまったところもありますがご了承ください……

また、スムーズにインストールできるように、自分がインストールした時の手順とは変更しています。そのため、ライブラリ依存によるエラーは発生しないようになっているはずです。

間違っていたらご指摘いただけるとうれしいです。

# 本記事での目標
* Python・JUMAN++・KNP・gensimでDoc2Vecを使うための環境構築
* 似た記事を抽出するサンプルプログラムの作成

# 環境
| key | value |
|----|----|
|OS|CentOS Linux release 7.3|
|shell|zsh 5.0|
|C++ compiler|gcc バージョン 4.8.5 20150623|
※bash使っているなら、.zshrcを.bash_profileとかに置き換えていただければと思います。

## インストールするもの
* [Python3](https://www.python.org/)
* [pip](https://pypi.python.org/pypi/pip)
* [gensim](https://radimrehurek.com/gensim/)
* [Boost](http://www.boost.org/)
* [JUMAN](http://nlp.ist.i.kyoto-u.ac.jp/?JUMAN)
* [JUMAN++](http://nlp.ist.i.kyoto-u.ac.jp/index.php?JUMAN++)
* [KNP](http://nlp.ist.i.kyoto-u.ac.jp/?KNP)
* [PyKNP](http://nlp.ist.i.kyoto-u.ac.jp/index.php?PyKNP)


# インストール内容
## Python3・pip
```sh:console
# Python3が入っているリポジトリを登録
sudo yum install -y https://centos7.iuscommunity.org/ius-release.rpm
# バージョン確認
yum search python36

# 必要と思われるものをインストール
sudo yum install -y python36 python36u python36u-libs python36u-devel python36u-pip
python3 -V

# シンボリックリンクがツリーっぽい形式になっている(python→python2→python2.7, python3→python3.6)
# デフォルトでは`python`はバージョン2にリンクしているため、バージョン3に変更したいが、yumが使用できなくなるためやらない
#ln -snf /usr/bin/python3 /usr/bin/python

# バージョン確認
python3 -V
# python -m がいらない場合もある
python3 -m pip -V
```

## gensim
```sh:console
sudo python3 -m pip install --upgrade gensim
```

## Boost(C++ライブラリ)
```sh:console
# 環境変数設定
echo 'export CPLUS_INCLUDE_PATH=$HOME/boost_1_64_0/include:$CPLUS_INCLUDE_PATH' >> .zshrc
echo 'export LD_LIBRARY_PATH=$HOME/boost_1_64_0/lib' >> .zshrc
## マイナーバージョンは固定しない
echo 'export PYTHONPATH=/usr/bin/python3' >> .zshrc
source .zshrc

# ※自分の環境では下記のようにwgetやcurlでは取得できなかった(404）ため、自端末(Windows)よりアップロード
# バージョン注意
curl 'https://dl.bintray.com/boostorg/release/1.64.0/source/:boost_1_64_0.tar.gz' > boost_1_64_0.tar.gz
tar xvzf boost_1_64_0.tar.gz
cd boost_1_64_0

./bootstrap.sh
# お好きなインストール先を指定
# ただし、/usr/bin以下は公式にて非推奨
# -jはCPU数+1が公式推奨
./b2 install -j2 --prefix=$HOME/boost_1_64_0 cxxflags="-std=c++11"
```

## JUMAN++(日本語形態素解析システム)
```sh:console
wget http://lotus.kuee.kyoto-u.ac.jp/nl-resource/jumanpp/jumanpp-1.01.tar.xz
tar xvzf jumanpp-1.01.tar.xz
cd jumanpp-1.01

./configure
make
sudo make install

# ライブラリの場所を登録
echo "include /usr/local/lib" >> /etc/ld.so.conf
sudo ldconfig

# パスを通す
cd ~
echo 'export PATH="${PATH}:/usr/local/lib"' >> .zshrc
source .zshrc

# バージョン確認
jumanpp -v

# 動作確認(数秒かかる)
echo "jumanppの動作確認" | jumanpp 
```

## JUMAN(同上)
```sh:console
curl http://nlp.ist.i.kyoto-u.ac.jp/DLcounter/lime.cgi?down=http://nlp.ist.i.kyoto-u.ac.jp/nl-resource/juman/juman-7.01.tar.bz2&name=juman-7.01.tar.bz2 > juman-7.01.tar.bz2
tar xvf juman-7.01.tar.bz2
cd juman-7.01

./configure
make
sudo make install

# バージョン確認
juman -v
```

## KNP(日本語等解析システム)
```sh:console
curl http://nlp.ist.i.kyoto-u.ac.jp/DLcounter/lime.cgi?down=http://nlp.ist.i.kyoto-u.ac.jp/nl-resource/knp/knp-4.17.tar.bz2&name=knp-4.17.tar.bz2 > knp-4.17.tar.bz2
tar xvf knp-4.17.tar.bz2
cd knp-4.17

# (オプションの指定はしていたか不明です……)
./configure --with-juman-prefix=/usr/local/juman
make
sudo make install

# JUMAN++とKNPの動作確認(数秒かかる)
echo "knpとjumanの動作確認" | jumanpp | knp
```

### PyKNP(KNPのPythonバインディング)
```sh:console
tar xvzf pyknp-0.3.tar.gz
cd pyknp-0.3

sudo python3 setup.py install
```

# Doc2Vecの使用
## 事前準備
```sh:console
mkdir data
cd data
# 学習用データのダウンロード
wget http://www.rondhuit.com/download/ldcc-20140209.tar.gz
tar xvfz ldcc-20140209.tar.gz
ls -p # → ldcc-20140209.tar.gz text/
cd ..
```

## サンプルプログラム
「[Doc2Vecの仕組みとgensimを使った文書類似度算出チュートリアル](https://deepage.net/machine_learning/2017/01/08/doc2vec.html)」のソースを参考にしました。

```py3:main.py
import sys
from os import listdir, path
from pyknp import Jumanpp
from gensim import models
from gensim.models.doc2vec import LabeledSentence


path_list = ["data/text/topic-news/topic-news-6903190.txt", "data/text/topic-news/topic-news-6907153.txt", "data/text/topic-news/topic-news-6909425.txt"]

def read_file(filepath):
    with open(filepath, "r") as f:
        return f.read()

def read_documents(paths):
    return [read_file(path) for path in paths]

def split_into_words_list(documents):
    for document in documents:
        applied_jumanpp = Jumanpp().analysis(document)
        yield [mrph.midasi for mrph in applied_jumanpp.mrph_list()]

def corpuses_to_sentences(splited_documents, path_list):
    for index, (text, path) in enumerate(zip(splited_documents, path_list)):
        print("preprocess {}", index)
        yield LabeledSentence(words=text, tags=[path])

def train_model(model, sentences, count):
    for epoch in range(count):
        model.train(sentences, total_examples=model.corpus_count, epochs=model.iter)
        model.alpha -= (0.025 - 0.0001) / 19
        model.min_alpha = model.alpha


if __name__ == '__main__':
    # データ作成
    documents = read_documents(path_list)
    splited_documents = split_into_words_list(documents)
    sentences = corpuses_to_sentences(splited_documents, path_list)
    
    # モデル作成
    model = models.Doc2Vec(sentences, dm=0, size=300, window=15, alpha=0.025, min_alpha=0.025, min_count=1, sample=1e-6, iter=1)
    
    # トレーニング
    train_model(model, sentences, 20)
    
    # モデルのファイル書き出し
    model.save("doc2vec.model")

```

## 実行
```sh:console
python3 main.py

# REPLで確認
python3
>> from gensim import models
>> model = models.Doc2Vec.load("doc2vec.model")
>> model.docvecs.most_similar("data/text/topic-news/topic-news-6903190.txt", topn=1)
# → [('data/text/topic-news/topic-news-6907153.txt', 0.0052252281457185745)]
```

## 補足
ダウンロードしたデータすべて（7,000ちょい）を学習した際には数十分かかりました。

# 発生したエラーと解決方法
1. `pyconfig.h: そのようなファイルやディレクトリはありません`
    * `export PYTHONPATH=[Pythonインストール先]`を.zshrcに書いて`source .zshrc`
1. Boostがインストールされていない。(エラーメッセージは失念、わかりやすい英語だった記憶。)
    * Boostをインストールする
1. `juman.h: not found.`
    * JUMAN++の他にJUMANをインストールする
1. REPLでの`model.docvecs.most_similar`呼び出し時、下記のエラーメッセージが出力される。
    * `model.docvecs.most_similar`の第一引数の文字列に、ソース内で使用しているパスと同じ文字列を指定する。
        * （タグとして使用しているため、完全一致でないといけないっぽい。`yield LabeledSentence(words=text, tags=[path])`の箇所。）

```sh:エラーメッセージ
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.6/site-packages/gensim/models/doc2vec.py", line 461, in most_similar
    elif doc in self.doctags or doc < self.count:
TypeError: '<' not supported between instances of 'str' and 'int'
```

# おわりに
意外に必要なライブラリが多く、時間がかかりました。今後のアップデートで変更されるかもしれませんが、とりあえず導入部分だけでも躓かないように、この記事を参考にしていただけたら幸いです。


# 参考ページ
1. Doc2Vecの仕組みとgensimを使った文書類似度算出チュートリアル
    * https://deepage.net/machine_learning/2017/01/08/doc2vec.html
1. livedoor ニュースコーパス
    * https://www.rondhuit.com/download.html#ldcc
1. Python 3 を CentOS 7 に yum でインストールする手順
    * http://weblabo.oscasierra.net/python3-centos7-yum-install/
1. Ubuntu 日本語形態素解析システムJUMANのインストール方法
    * http://www.trifields.jp/how-to-install-juman-in-ubuntu-1404-1375
1. JUMAN++をPythonから使う
    * http://qiita.com/riverwell/items/7a85ebf95647eaf18a6c
1. CentOS 6.0 gcc 4.7.2にBoost 1.5.0をインストール
    * http://qiita.com/sincrinc/items/bcde85868bb03717cabd