機械学習のための前処理 (scikit-learn Preprocessing)

# 機械学習の前処理とは

AIは生のデータから学習すると思っていたけれども、実施はデータの前処理が必要になるケースが多々あるようです。

[Should I standardize the input variables (column vectors)?](http://www.faqs.org/faqs/ai-faq/neural-nets/part2/section-16.html)

上のサイトによると、機械学習への寄与が入力の大きさに影響するようなので、使用する機械学習のアルゴリズムごとに、入力を適切にスケーリング (標準化) することが必要らしいです。 (理解が間違っていなければ、、、)

# Scikit learnによる前処理

PythonのライブラリのScikit learnでは、この前処理を一括で行う関数が用意されています。下記のサイトにも、具体例が載っていますが、具体例で使用されている3x3行列では、いまいちイメージが沸かなかったので、どのような前処理が行われているのか、試してみました。

http://scikit-learn.org/stable/modules/preprocessing.html

### 処理の対象とする行列の作成

10x3行列を使って、Scikit learnの前処理でどのような処理が行われるのか確認します。

```python:test.py

import numpy as np
from sklearn import preprocessing

a = [i**2 - 420 for i in range(30)]
a = np.array(a)
a = a.reshape(10,3)
print(a)
print(a.max(axis=0)) # 各列の最大値 [309 364 421]
print(a.min(axis=0)) # 各列の最小値 [-420 -419 -416]
print(a.mean(axis=0)) # 各列の平均 [-163.5 -135.5 -105.5]
print(a.var(axis=0)) # 各列の分散 [58405.05 66721.05 75631.05]

"""
行列 a:
[[-420 -419 -416]
 [-411 -404 -395]
 [-384 -371 -356]
 [-339 -320 -299]
 [-276 -251 -224]
 [-195 -164 -131]
 [ -96  -59  -20]
 [  21   64  109]
 [ 156  205  256]
 [ 309  364  421]]
"""
```

### Scale関数による前処理

各列は、平均 0 、分散 1に標準化されます。

```python:test2.py

a_scaled = preprocessing.scale(a)

print(a_scaled.max(axis=0)) # [1.95513438 1.93376661 1.91446888]
print(a_scaled.min(axis=0)) # [-1.06135866 -1.09754321 -1.12904575]
print(a_scaled.mean(axis=0)) # [ 2.22044605e-17 -8.88178420e-17  6.66133815e-17]
print(a_scaled.var(axis=0)) # [1. 1. 1.]

```
### MinMaxScaler関数による前処理

各列は、最大値 1 、最小値 0 に標準化されます。

```python:test3.py

min_max_scaler = preprocessing.MinMaxScaler()
a_minmax = min_max_scaler.fit_transform(a)

print(a_minmax.max(axis=0)) # [1. 1. 1.]
print(a_minmax.min(axis=0)) # [0. 0. 0.]
print(a_minmax.mean(axis=0)) # [0.35185185 0.36206897 0.37096774]
print(a_minmax.var(axis=0)) # [0.10989941 0.10882767 0.1079566 ]

```

### MaxAbsScaler関数による前処理

各列は、最大、最小の絶対値が 1 に標準化されます。
各列の要素がすべて正の値の場合は、MaxMinScaler関数と同じ結果を返すようです。

```python:test4.py

max_abs_scaler = preprocessing.MaxAbsScaler()
a_maxabs = max_abs_scaler.fit_transform(a)

print(a_maxabs.max(axis=0)) # [0.73571429 0.86873508 1.        ]
print(a_maxabs.min(axis=0)) # [-1.         -1.         -0.98812352]
print(a_maxabs.mean(axis=0)) # [-0.38928571 -0.32338902 -0.25059382]
print(a_maxabs.var(axis=0)) # [0.33109439 0.38004483 0.42671306]

```

# Pandasに対して前処理を行いたい
上記のScikit-learnの前処理は、前処理結果がndarrayに変換されてしまいます。
このため、元DataがPandasである場合、前処理結果がPandasでなくなってしまうことが面倒です。
その面倒を回避するには、下記のライブラリを使用すると良さそうです。作ってくれた人、ありがとうございます。

[StatsFragments Python, R, Rust, 統計, 機械学習とか] (http://sinhrks.hatenablog.com/entry/2015/03/18/003954)
[Github sinhrks/pandas-ml](https://github.com/sinhrks/pandas-ml)

# どの前処理を用いるか?

前回行った試行によると、LSTMで予測を行う場合は、平均値0のデータの場合が予測精度が高かった。その場合、Scale関数を使って前処理を行うと良いかもしれない (未検証)。

[LSTMの予測精度に対するサンプルデータ絶対値の影響](https://qiita.com/AfricaUmare/items/14ca56f175a864efef64)

- Scale関数で標準化している例
    - [TensorFlow(LSTM)で株価予想 〜 株予想その１ 〜](https://qiita.com/tsunaki/items/a5f3f975a31dc45fc9c9)
- MaxMinScaler関数で標準化している例
    - [LSTMで仮想通貨の価格予測をする](https://qiita.com/licht110/items/f89c699cbdff05ec90de)
- 標準化していない(?)例 | 絶対値が小さければ標準化しなくてもよい?
    - [仮想通貨取引所のPoloniexからAPI経由でデータ取得し、ディープラーニング（Chainer）で翌日の価格予測をしよう](https://qiita.com/yoshizaki_kkgk/items/79f4056901dd9c059afb)