機械学習（scikit-learn）を使用した株価予想

scikit-learnを勉強してみたので、そちらを使って株価を予想してみる話。
[前回](http://qiita.com/yai/items/8c0ad280cc2f53e40256)、[前々回](http://qiita.com/yai/items/5ec5bbfbcc53c9770c40)とネタが被っているのはTensorFlowと比較したいのと、入力に使うデータの入手や加工が面倒なためです。お許しください。
ちなみに既に[同様のことをやられている方](http://qiita.com/ynakayama/items/6a472e5ebbe9365186bd)がいらっしゃいます。
なお、1週間くらいscikit-learn（およびその周りの理論等）を勉強しただけなので間違い等多分にあると思います。指摘等お待ちしています。

##scikit-learnとは
「サイキット・ラーン」と読むっぽい。
機械学習のためのライブラリ。色々なアルゴリズムが搭載されていて割と簡単に使える。
TensorFlowでも同じようなことが出来るのかもしれないが、scikit-learnの方が書くのが楽。

####メリット
- 様々なアルゴリズムが使える。
- Windowsで動く。（コレ大事）

####デメリット
- ディープラーニングは出来ない。

##趣旨
- scikit-learnを試す。
- TensorFlowを使用したときと比べて、使用感、精度、速度等を見る。

##やること
「数日分の世界中の株価指数（ダウ、日経平均、DAXなど）を使用して、次の日の日経平均が上がるか下がるか（2択）を予想する」（前回と変わらず）

##環境
scikit-learn 0.17.1
Python 2.7
Windows 7

##実装
###準備
前回のデータをそのまま流用します。
（[Quandl](https://www.quandl.com/data/YAHOO)というサイトからダウンロードした、日経、ダウ、香港ハンセン、ドイツの株価指数をテキストデータとして1つにまとめたもの）

###ラベル
scikit-learnの場合、ラベルはフラグ形式（[0,0,1]みたいなの）ではなく、intで数値を指定するようなので、上昇の場合は0、下落の場合は1としました。

```
if array_base[i][3] > (array_base[i+1][3]):
    y_flg_array.append(0)
    up += 1
else:
    y_flg_array.append(1)
    down += 1
```
サンプル全体としては、
上がる：50.5%
下がる：49.5%
となりました。

###入力データ
前回の改善点を踏まえ、株価をそのまま入れるのではなく、「前日に比べてどれくらい（%）上下したか」のリストを与えています。

```
tmp_array = []
for j in xrange(i+1, i + data_num + 1):
    for k in range(16):
        tmp_array.append((array_base[j][k] - array_base[j+1][k]) / array_base[j][k] * 100)
x_array.append(tmp_array)
```

###分類アルゴリズム
scikit-learnでは色々なアルゴリズムが使えますが、正直どれが良いのかサッパリ分からないので、なんとなくそれっぽいものを3つほど試してみることにしました。
今回試すのは、確率的勾配降下法、決定木、サポートベクターマシンの3つです。
ちなみにこの3つがどのように違うのかは全く分かっておりません。(^_^;)

```
# SGDClassifier
clf = linear_model.SGDClassifier()
testClf(clf, x_train_array, y_flg_train_array, x_test_array, y_flg_test_array)

# Decision Tree
clf = tree.DecisionTreeClassifier()
testClf(clf, x_train_array, y_flg_train_array, x_test_array, y_flg_test_array)

# SVM
clf = svm.SVC()
testClf(clf, x_train_array, y_flg_train_array, x_test_array, y_flg_test_array)
```

###訓練、評価
関数内で訓練と評価をやるようにしました。訓練はfit()を実行するだけ、評価はscore()を実行するなので非常に楽です。

```
def testClf(clf, x_train_array, y_flg_train_array, x_test_array, y_flg_test_array):

    print clf
    clf.fit(x_train_array, y_flg_train_array)
    print clf.score(x_test_array, y_flg_test_array)
```

##結果  ～その１～

```
SGDClassifier : 0.56591099916
DecisionTreeClassifier : 0.544080604534
SVM : 0.612090680101
```
TensorFlow使用時に63%程度の正答率だったので、そこまでではありませんがそれなりの結果は出ている模様。
SVMだけ処理が重め。
※たまに聞かれますが、訓練用とテスト用でデータは分けています。全体の8割を訓練、2割をテストに使用しています。

##パラメータ調整
上記では各分類器のインスタンス作成時に、引数に何も指定しませんでしたが、パラメータを調整することで精度を上げられたりするようです。
さらに、このパラメータを総当りで探してくれる機能もあります。便利。
一番良い結果を出したSVMで試してみます。

```
clf = svm.SVC()
grid = grid_search.GridSearchCV(estimator=clf, param_grid={'kernel': ['rbf','linear','poly','sigmoid']})
grid.fit(x_train_array, y_flg_train_array)
testClf(grid.best_estimator_, x_train_array, y_flg_train_array, x_test_array, y_flg_test_array)
```
上記では、SVMのkernelを'rbf','linear','poly','sigmoid'の4つで試し、1番良いパラメータで再度訓練とテストをしています。（訓練はもう不要なのかな？）
余談ですが、もちろんkernelの意味などはよく分かっておりません。(^_^;)

##結果～その２～

```
0.638958858102
```
最も良い結果を出したのは、kernelがlinearの場合で、若干ですが精度が上がりました。
約64%、・・・アレ？ディープラーニングを超えちゃったぞ・・・（誤差範囲でしょうが）

##考察
- やっぱり入力は株価をそのまま入れるより、変化率等にしておいた方が良い。（株価そのままでやってみたら上手くいかなかった）
- ディープラーニングの人気が高いですが、それ以外でも割と頑張れる。

##所感
- アルゴリズム等が全然分かってなくても割と簡単に動かせて楽しい。
- グリッドサーチ（パラメータを総当りする機能）はそれなりに時間がかかる。パラメータを複数試すならスペックか覚悟が必要。（コレが「次元の呪い」という話か？）
- 関係ないけど、今回開発にEclipseを使いました（今まではテキストエディタ）。超楽です。
- scikit-learnの日本語情報少な過ぎ。誰か公式チュートリアル等を和訳してくれないだろうか・・・

##参考にしたサイト
- [公式チュートリアル](http://scikit-learn.org/stable/tutorial/index.html)
- [公式APIリファレンス](http://scikit-learn.org/stable/modules/classes.html)
- [機械学習で未来を予測する - scikit-learn の決定木で未来の株価を予測](http://qiita.com/ynakayama/items/6a472e5ebbe9365186bd)