隠れマルコフモデルを実現するPythonライブラリ hmmlearnの使い方

hmmlearnの日本語情報が見当たらなかったので最低限の使い方をまとめました。
※Tutorial + α 程度です。

hmmlearnはHMM(隠れマルコフモデル)を実現するscikit-learnライクなPythonライブラリです。
http://hmmlearn.readthedocs.org

# セットアップ
以下の導入が必須になります。
※Pythonは3系でも動作確認済みです。

* Python >= 2.6
* NumPy(tested to work with >= 1.9.3)
* SciPy(tested to work with >= 0.16.0)
* scikit-learn >= 0.16

## インストール
hmmlearnはpipでインストールすることができます。

```bash
$ pip install -U --user hmmlearn
```

# 使い方
今回はGaussianHMMを利用します。

### GaussianHMMとは
モデルの出力が連続値となる隠れマルコフモデルです。

### 必要なパラメータ
以下の方法でmodelのインスタンスを作成します。

```python
from hmmlearn import hmm

model = hmm.GaussianHMM(n_components=3, covariance_type="full")
```
引数のn_componetsは状態数を指定して、covariance_typeは共分散の種類を指定します。

指定が必須となる属性は以下となります。

* startprob_
    * 初期状態の遷移確率を指定します。(状態数 * 1)
* transmat_
    * 状態遷移確率を指定します。(状態数 * 状態数)
* means_
    * 各状態の平均を指定します。(状態数 * 特徴数)
* covars_
    * 共分散を指定します。(covariance_typeによる)


今回は例で状態数を５個としてパラメータを入れました。

```python
import numpy as np
from hmmlearn import hmm


startprob = np.array([0.0, 0.1, 0.8, 0.1, 0.0])
transmat = np.array([[0.9, 0.1, 0.0, 0.0, 0.0],
                     [0.4, 0.3, 0.3, 0.0, 0.0],
                     [0.1, 0.2, 0.4, 0.3, 0.0],
                     [0.0, 0.1, 0.3, 0.3, 0.3],
                     [0.0, 0.0, 0.3, 0.1, 0.6]])

means = np.array([[1.0, 1.0],
                  [2.0, 2.0],
                  [3.0, 3.0],
                  [4.0, 4.0],
                  [5.0, 5.0]])

covars = 0.1 * np.tile(np.identity(2), (5, 1, 1))

model = hmm.GaussianHMM(n_components=5, covariance_type="full")

model.startprob_ = startprob
model.transmat_ = transmat
model.means_ = means
model.covars_ = covars
```

## 予測
サンプルデータで状態系列を予測してみます。

```python
>>> X, Z = model.sample(10)

>>> print(X)
[[ 3.42184743  2.84259768]
 [ 1.83591345  2.60456015]
 [ 3.0610817   3.67242462]
 [ 3.88970955  3.94599461]
 [ 4.99679025  5.21663028]
 [ 5.05294062  4.80691392]
 [ 5.25836686  5.08960965]
 [ 5.49849546  5.00469741]
 [ 5.31740667  4.77140169]
 [ 4.1283215   5.06959465]]

>>> print(Z)
[2 1 2 3 4 4 4 4 4 4]
```
これはサンプルデータがXのとき状態系列はZと予測された結果です。


サンプルではないデータから状態系列を予測してみます。
ある出力系列をもとに状態系列を予測する場合はpredictメソッドを使用します。

```
>>> model.predict([[1.3], [2.0], [4.3], [4.2]])
array([1, 2, 3, 3])
```

## 学習
パラメータを学習によって推定する方法を紹介します。

fitメソッドによって学習を行いパラメータ推定を行います。
今回はXを学習データとしています。

```python
import numpy as np
from hmmlearn import hmm

model = hmm.GaussianHMM(n_components=5, covariance_type="full")
X = np.array([[1.2], [2.3], [1.1], [4.2], [3.3]])
model.fit(X)
```

学習によってパラメータが入力されていることが確認できます。

```python
>>> model.startprob_
array([  2.06946712e-292,   0.00000000e+000,   3.13184994e-003,
         1.27702612e-300,   9.96868150e-001])
        
>>> model.means_
array([[ 2.3       ],
       [ 4.2       ],
       [ 1.10171369],
       [ 3.3       ],
       [ 1.15485602]])
       
>>> model.covars_
array([[[ 0.01      ]],
       [[ 0.01      ]],
       [[ 0.05488646]],
       [[ 0.01      ]],
       [[ 0.00797925]]])
       
>>> model.transmat_
array([[  1.27206138e-223,   1.57268167e-192,   1.79623272e-001,
          9.10036066e-211,   8.20376728e-001],
       [  5.88225536e-075,   2.07494122e-025,   1.88590294e-063,
          1.00000000e+000,   5.18696363e-119],
       [  1.71368655e-002,   9.82863134e-001,   6.65061859e-190,
          9.25847733e-045,   3.48719264e-293],
       [  1.79414943e-074,   2.06495338e-025,   3.28132831e-011,
          1.00000000e+000,   1.50081312e-010],
       [  5.48560165e-001,   4.51439835e-001,   1.32144625e-190,
          6.49028218e-045,   0.00000000e+000]])

```

## 評価
モデルを評価するために対数尤度を求めます。

scoreメソッドによってモデルの評価を行います。
評価するための出力系列をXに指定します。

```python
>>> X = np.array([[3.2], [2.4], [3.1], [3.2], [3.0], [3.9], [4.0]])
>>> model.score(X)
0.11878179338435844
```

## 書き出しと読み込み
モデルの書き出しと読み込みを行います。

sklearnのjoblibを使うことによってモデルを書き出すことができます。

```python
>>> from sklearn.externals import joblib
>>> joblib.dump(remodel, "filename.pkl")
["filename.pkl"]
```

読み込みも同じようにjoblibを使ってloadメソッドにより読み込みができます。

```python
>>> from sklearn.externals import joblib
>>> joblib.load('filename.pkl')
GaussianHMM(algorithm='viterbi', covariance_type='full', covars_prior=0.01,
      covars_weight=1, init_params='stmc', means_prior=0, means_weight=0,
      min_covar=0.001, n_components=5, n_iter=10, params='stmc',
      random_state=None, startprob_prior=1.0, tol=0.01, transmat_prior=1.0,
      verbose=False)
```