機械学習を用いた株価予測(っぽいもの)

`scikit-learn`を用いたランダムフォレストアルゴリズムを利用して、株価予測**ぽいもの**を行い、機械学習の一端に触れる。

#1,目的

- `scikit-learn`を用いた株価予測アプリケーションを通じて機械学習の一端に触れる
- あわよくば一儲けしたい()

#2,機械学習とは？
総務省の資料によると
> データから規則性や判断基準を学習し、それに基づき未知のものを予測、判断する技術
(http://www.soumu.go.jp/ict_skill/pdf/ict_skill_3_5.pdf)

NVIDIAの資料によると
> 世の中の特定の事象についてデータを解析し、その結果から学習して、判断や予測を行うためのアルゴリズムを使用する手法
[NVIDIA](https://blogs.nvidia.co.jp/2016/08/09/whats-difference-artificial-intelligence-machine-learning-deep-learning-ai/)

どちらも似たようなことを言っています。
基本として**データ**から**学習**して**予測**するのが機械学習になるようです。
また、与えるデータは何でもかんでも無節操に与えるわけではなく、プログラマー側で取捨選択し、そのデータの**特徴**を抽出してプログラムに与える必要があります。
当然データ量や質、特徴の抜き出し方によって異なる結果になることも十分に考えられます。

また、似たような言葉にAIやディープラーニングなどもありますが、今のところ下記のような包括関係になっているようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292905/6a72bf24-2df3-f43f-dd9f-32b535cf95af.png)
[NVIDIA](https://blogs.nvidia.co.jp/2016/08/09/whats-difference-artificial-intelligence-machine-learning-deep-learning-ai/)

#3,ランダムフォレストとは？

ランダムフォレストは、各種ある機械学習の為のアルゴリズムの中の一つで、多数の**決定木**の多数決により結果を求める手法になります。

決定木とはその名の通り、**分類や回帰のルールを木構造で表した**ものになり、あるデータを入力すると通常の木構造のように節を順々に辿り、最終的に葉にたどり着くようになっています。決定木の節はそれぞれ分類ルールを表しており、最終的な葉には結果が記述されています。

ランダムフォレスト全体としては、決定木を複数持ち、それぞれの決定木で異なる分類ルールを定めるようにします。実際にデータが入力された際はそれぞれの決定木の結果の多数決により最終的な結論を出します。
それぞれの決定木の分類ルールは与えられた学習用データから、決定木の性質に偏りが出ないような方針で作成されます。

#4,実装
今回は[株式投資メモ](https://kabuoji3.com/stock/)より株価のCSVデータを取得して使用しています。

##4-1,環境
- python 3.6.8
- scikit-learn 0.20.2
- pandas 0.24.0

##4-2,ソース
```python:StockPricePredicting.py
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn import metrics
import sys


#CSVファイルを取り込み、その後の操作をしやすいように変換する
csv = pd.read_csv(sys.argv[1]).sort_values(["date"])
csv = csv[["date", "start", "high", "low", "close"]]

#今回のラベルとなるリザルトカラムを作成
csv["result"] = csv["close"]/csv["start"].shift(-1)
csv = csv.drop(index = 0)

#トレーニングデータとテストデータを分割
data_train, data_test, prov_label_train, prov_label_test = train_test_split(csv[['start', 'high', 'low', 'close']], csv['result'])

#株価が上がるか下がるかだけ確認するため、ラベルの数値を操作
label_train = [1 if l - 1.0 >= 0 else -1 for l in prov_label_train]
label_test = [1 if l - 1.0 >= 0 else -1 for l in prov_label_test]

#ランダムフォレストで学習結果を格納
clf = RandomForestClassifier()
clf.fit(data_train, label_train)

#学習結果を用いてテストデータから結果を予想
predict = clf.predict(data_test)

#結果を表示
ac_score = metrics.accuracy_score(label_test, predict)
cl_report = metrics.classification_report(label_test, predict)
print("正解率", ac_score)
print("レポート", cl_report)

```

##4-3,解説

```python
csv = pd.read_csv(sys.argv[1]).sort_values(["date"])
csv = csv[["date", "start", "high", "low", "close"]]
```
今回の機械学習で必要なデータはcsvファイルでまとめられています。
csvのパスをコマンドライン引数で渡して、そのcsvファイルを読み込みます。
csvファイルを取り扱うにあたって便利なライブラリが``pnadas``になります。
今回はデータの整形程度にしか利用していませんが、欠損値の置き換えなどもできるようです。
csvの中身は該当の日付、始値、高値、安値、終値という構成になっています。

```python
csv["result"] = csv["close"]/csv["start"].shift(-1)
csv = csv.drop(index = 0)
```
また、今回機械学習で知りたいのは、次の日の株価が上がるか下がるかという事柄です。機械学習において、この答というのは``ラベル``と言われます。この問題と答えとなるラベルの関係性は、ただデータを渡しただけではプログラム側はわからない為、こちらで指定する必要があります。
そこで、終値を始値で割った値をラベルとします。さらに次の日の株価の変遷がしたい為、全体として一日ずつラベルをずらしています。
このため最新の日付のデータはNaNになってしまうため削除しています。


```python
#トレーニングデータとテストデータを分割
data_train, data_test, prov_label_train, prov_label_test = train_test_split(csv[['start', 'high', 'low', 'close']], csv['result'])

#株価が上がるか下がるかだけ確認するため、ラベルの数値を操作
label_train = [1 if l - 1.0 >= 0 else -1 for l in prov_label_train]
label_test = [1 if l - 1.0 >= 0 else -1 for l in prov_label_test]
```

前述したように、プログラム側に問題とラベルの指定をするため、またトレーニング用のデータと、そのトレーニング結果を確認するためのテストデータとを分割します。
またラベルの値はその定義から1より大きければ株価が上昇し、小さければ株価が下降します。
その幅は今回問題としていないのと、単純に結果としての見やすさから、上がるか下がるかで1 or -1と書き換えます。

```python
#ランダムフォレストで学習結果を格納
clf = RandomForestClassifier()
clf.fit(data_train, label_train)

#学習結果を用いてテストデータから結果を予想
predict = clf.predict(data_test)
```

ここはこちら側から特に特別な操作をくわえていません。関数にデータを渡して学習結果を保存し、テストデータで確認をおこないます。

```python
#結果を表示
ac_score = metrics.accuracy_score(label_test, predict)
cl_report = metrics.classification_report(label_test, predict)
print("正解率", ac_score)
print("レポート", cl_report)
```

こちらも特になにもやっていませんが、学習結果の確認を行います。

#5,結果
今回の機械学習では、大体正解率が40～60%の範囲になりました。
そもそも正解率の誤差が大きく、この手法、データで十分かという疑問がありますが。少なくともこの学習結果で儲けるのは難しいと考えられます。
取りあえず今回は裏でどういった作業をやっているかを考えず、機械学習に触れるだけを目的にしましたが、今後もう少し詳しくやっていきたいです。