Macにおける日本語文章分類環境構築（Doc2Vec, Juman++）

# はじめに
この記事では、Mac環境においてDoc2VecとJuman++による日本語文章分類を行うための環境構築手順についてまとめます。極力パッケージ管理ツールを使用することを方針とします。環境構築が主目的なのでDoc2VecやJuman++の詳細には触れません。

# 環境
以下の環境を構築します。

|環境名  | バージョン | 入手元 |
|:-------:|:------------:|-----|
|OS     |macOS Sierra|-|
|Python|3.6.6rc1| 公式からダウンロード|
|KNP    |4.1.9 |Homebrew
|Juman++|1.0.2 |Homebrew
|PyKNP  |0.3 |公式からダウンロード|
|gensim|3.4.0|pip|

HomebrewやPythonはインストール済みとします。

# 手順
環境構築に必要な手順は大きく分けて、

* 形態素解析ライブラリJuman++のインストール
* Doc2Vecライブラリgensimのインストール

になります。


## 形態素解析ライブラリJuman++のインストール
日本語の形態素解析ライブラリはMecabが有名ですが、[最近はJuman++なるものも使われる](https://qiita.com/riverwell/items/438e88427363511e9f28)みたいです。今回私はブログ記事の分類をしたかったため、そちらに向いているとされるJuman++の方を使用します。

また、Pythonを開発言語として使用するため、以下のパッケージをインストールする必要があります。

* KNP（構文解析システム）
* Juman++（形態素解析システム）
* PyKNP（KNPとJuman++のPythonバインディング）

 
### KNPのインストール
構文解析システムのKNPをインストールします。KNPはデフォルトのHomebrewリポジトリに含まれていないので、自然言語処理に関連するライブラリに特化したHomebrewリポジトリnlpからインストールします。結構時間がかかるので要注意です。

```bash:console
brew tap uetchy/nlp
brew install knp
```
### Juman++のインストール
形態素解析システムのJuman++をインストールします。こちらはデフォルトのHomebrewリポジトリに含まれているのでそのままインストールできます。

```bash:console
brew install jumanpp
```

### PyKNPのインストール
KNPとJuman++のPythonバインディングのPyKNPはpipに含まれていなので自前でビルドしてインストールします。

```bash:console
wget http://nlp.ist.i.kyoto-u.ac.jp/nl-resource/knp/pyknp-0.3.tar.gz
tar xvf pyknp-0.3.tar.gz
cd pyknp-0.3
sudo python setup.py install
```

## Doc2Vecライブラリgensimのインストール

#### gensimのインストール
pipでインストールできます。

```bash:console
pip install gensim
```

# 動作確認
## 確認用データ
確認用データにはlivedoorニュースコーパスを使用しました。

```bash:console
wget http://www.rondhuit.com/download/ldcc-20140209.tar.gz
tar xvfz ldcc-20140209.tar.gz
```
tarを解答するとtextというフォルダが展開され、そこに大量のテキストデータが入っています。

## 確認用コード
いくつか既存のコード例がありますが、今回の環境のバージョンだと動かなかったため、動作確認用コードを書きました。

* ドキュメントに半角スペースが含まれていると上手く処理できない
* `Jumanpp().analysis()`は改行コードがあるところまでしか処理しない

というところで少しつまづきましたが、

* 半角スペースを全角スペースに置換する
* 予めドキュメントを一行ずつ抽出して`Jumanpp().analysis()`に投げる

ことで解決しました。

```python:doc2vec_ex.py
from pyknp import Jumanpp
from gensim import models
from gensim.models.doc2vec import TaggedDocument


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


def normalized_sentence(sentence):
    return sentence.replace(' ', '　')


def parse_words(filepath):
    with open(filepath, encoding='utf-8') as f:
        document = f.read()
        words = []
        for sentence in filter(None, document.split('\n')):
            result = Jumanpp().analysis(normalized_sentence(sentence))
            words += [mrph.midasi for mrph in result.mrph_list()]
        return words


class TaggedFileDocuments(object):
    def __init__(self, path_list):
        self.path_list = path_list

    def __iter__(self):
        for file_path in self.path_list:
            yield TaggedDocument(words=parse_words(file_path), tags=[file_path])



if __name__ == '__main__':
    # データ作成
    documents = TaggedFileDocuments(path_list)

    # モデル作成
    model = models.Doc2Vec(documents,
                           dm=0,
                           vector_size=300,
                           workers=4,
                           window=15,
                           alpha=0.025,
                           min_alpha=0.025,
                           min_count=1,
                           sample=1e-6,
                           epochs=20)

    # モデルのファイル書き出し
    model.save("doc2vec.model")
```

## 確認結果
 ```bash:console
python3 doc2vec_ex.py
python3
>>> from gensim import models
>>> model = models.Doc2Vec.load('doc2vec.model')
>>> model.docvecs.most_similar("text/topic-news/topic-news-6903190.txt", topn=1)
[('data/text/topic-news/topic-news-6907153.txt', 0.3459581732749939)]
```
生成したモデルから、指定した文章に最も類似する文章とその類似度を抽出できました。

# 参考
1. [Doc2Vecを使用するまでの環境構築手順](https://qiita.com/talog/items/2675e234bb258682293a)
* [Doc2Vecの仕組みとgensimを使った文書類似度算出チュートリアル](https://deepage.net/machine_learning/2017/01/08/doc2vec.html)
* [HomebrewでOSXに構文解析システムKNPを入れる](https://qiita.com/uetchy/items/3284ba1de1df39166744)
* [JUMAN++を使って苦労したこと](https://qiita.com/trtd56/items/2f62a390eb8fab92e801)
* [Doc2Vec Tutorial on the Lee Dataset](https://github.com/RaRe-Technologies/gensim/blob/develop/docs/notebooks/doc2vec-lee.ipynb)