時系列データを対象にした機械学習手法の比較

## 前書き
機械学習の手法をペラペラと調べていると、サンプルとして示されている問題はirisのような
表形式のデータの場合が多いです。

（以下の様なデータをイメージしていただければ・・・）

|no  |がく片の長さ |がく片の幅 |... |
|---|---|---|---|
|1  |1.2  |3.4  |...
|2  |2.5  |1.8  |...
|... |... |... |... |

しかし、世の中のデータを見てみると、時間の前後関係がある様なデータも
数多くあることがわかります。また、そういったデータに対して分析する需要があることも想像できます。
（例えば、一週間の電力消費量の推移から、来週の電力消費量の予測等）

ということで、時系列データに対して機械学習を（そのまんま）適用して、
どの様な結果となるか見てみたいと思った次第であります。

今回対象にするのは以下の手法です。

* 近傍法
* 決定木
* ランダムフォレスト
* CNN

（その他手法もにつきましては、時間不足で比較できませんでした。申し訳ありません汗）

## 前準備

+ python
+ sklearn
+ tensorflow
+ keras
+ pandas
+ numpy
+ 評価データ ([UCR Time Series Classification Archive](http://www.cs.ucr.edu/~eamonn/time_series_data/))

足りないものあれば適宜pip等でインストールしていただければ幸いです。

## 実装

### ディレクトリ構成
評価データをdataフォルダに格納します。
サンプルだと”Adiac”のみを使用しているので、自分にあった使いたい
データセットを格納してください。

```
estimator_test
├── UCR_TS_Archive_2015
│   ├── Adiac
│   ...
│   └── yoga
│
└── ed_knn.py
    dtree.py
    rforest.py
    fcn.py
```

## ed_knn.pyの中身

最近傍法

```python
# -*- coding: utf-8 -*-

import numpy as np
import pandas as pd
from sklearn import metrics
from sklearn.neighbors import KNeighborsClassifier

flist = ['Adiac']
dir_name = "UCR_TS_Archive_2015/"


def readucr(filename):
    data = np.loadtxt(filename, delimiter = ',')
    Y = data[:,0]
    X = data[:,1:]
    return X, Y


def make_data(path):
    x_train, y_train = readucr(dir_name + path + '/' + path + '_TRAIN')
    x_test, y_test = readucr(dir_name + path + '/' + path + '_TEST')
    
    # ラベルを0オリジンに統一
    nb_classes =len(np.unique(y_test))
    y_train = (y_train - y_train.min())/(y_train.max()-y_train.min())*(nb_classes-1)
    y_test = (y_test - y_test.min())/(y_test.max()-y_test.min())*(nb_classes-1)
    
    # 入力データの正規化
    x_train_mean = x_train.mean()
    x_train_std = x_train.std()
    x_train = (x_train - x_train_mean)/(x_train_std)
    x_test = (x_test - x_train_mean)/(x_train_std)

    return x_train, y_train, x_test, y_test


def MAIN():
    for fname in flist:
        x_train, y_train, x_test, y_test= make_data(fname)
        # print(x_train, y_train, x_test, y_test )

        # p=2でユークリッド距離を使用
        knn = KNeighborsClassifier(n_neighbors=1, p=2)

        knn.fit(x_train, y_train)
        y_train_pred = knn.predict(x_train)
        y_test_pred = knn.predict(x_test)

        ed_1nn_train_accuracy = metrics.accuracy_score(y_train, y_train_pred)
        ed_1nn_test_accuracy = metrics.accuracy_score(y_test, y_test_pred)
        print("train_ed_1nn_score = " + str(ed_1nn_train_accuracy))
        print("test_ed_1nn_score = " + str(ed_1nn_test_accuracy))


if __name__ == '__main__':
    MAIN()
```

## dtree.pyの中身

決定木(最近傍方の差分のみ)

```python
def MAIN():
    for fname in flist:
        x_train, y_train, x_test, y_test= make_data(fname)
        # print(x_train, y_train, x_test, y_test )

        dtree = DecisionTreeClassifier()

        dtree.fit(x_train, y_train)
        y_train_pred = dtree.predict(x_train)
        y_test_pred = dtree.predict(x_test)

        dtree_train_accuracy = metrics.accuracy_score(y_train, y_train_pred)
        dtree_test_accuracy = metrics.accuracy_score(y_test, y_test_pred)
        print("train_dtree_score = " + str(dtree_train_accuracy))
        print("test_dtree_score = " + str(dtree_test_accuracy))
```

## rforest.pyの中身

ランダムフォレスト(最近傍方の差分のみ)

```python
    for fname in flist:
        x_train, y_train, x_test, y_test= make_data(fname)
        # print(x_train, y_train, x_test, y_test )

        rforest = RandomForestClassifier()

        rforest.fit(x_train, y_train)
        y_train_pred = rforest.predict(x_train)
        y_test_pred = rforest.predict(x_test)

        rforest_train_accuracy = metrics.accuracy_score(y_train, y_train_pred)
        rforest_test_accuracy = metrics.accuracy_score(y_test, y_test_pred)
        print("train_rforest_score = " + str(rforest_train_accuracy))
        print("test_rforest_score = " + str(rforest_test_accuracy))
```

## fcn.pyの中身

CNN

以前紹介させていただいた、時系列データ向けCNN(fcn.py)を適用しています。
https://github.com/cauchyturing/UCR_Time_Series_Classification_Deep_Learning_Baseline
ただし、検証データにテストデータを使用しない様に変更しています。

## 結果
各手法の学習データ、テストデータの正解率を示します。

|data  |最近傍法 |決定木 |ランダムフォレスト |CNN |
|---|---|---|---|---|
|Adiac_train  |1.0  |1.0  |0.99 |1.0 |
|Adiac_test  |0.61  |5.2  |0.58 |0.82 |

データが少ないことも起因してか過学習っぽいですね。

## 所感
決定木とランダムフォレストが、あまりよろしくない結果となりました。
生データを直接入力するのではなく、別の特徴量に変換しないと中々思った通りの結果にならないのかもしれません。
また、パラメータチューニングも一切行っていませんので、その辺りも伸び代になるかもしれません。

今度はDTW等の時系列データ向けの解析手法を使って何かできたらいいなと思います。