Azure Machine Learning Studio で時系列データ予測してみた

これは [日本情報クリエイト Engineer's Advent Calendar 2017](http://qiita.com/advent-calendar/2017/njc) の1日目の記事です。

Merry Christmas! 🎅

# はじめに

## 目的
複雑な話は無しにして、
[Microsoft Azure Machine Learning Studio](https://studio.azureml.net/)（以下、ML Studio）を一通り

* 学習・テストデータ作成
* 学習フローの作成
* 学習
* 予測
* 学習モデルの性能評価
* 予測データの利用

体験すること。

## きっかけ
ML Studio を知ったのはつい最近のことです。
[チュートリアル](https://docs.microsoft.com/ja-jp/azure/machine-learning/studio/create-experiment)や他の方が書かれた記事を読み、こう感じました。
**「なんだこれ、楽しそう！」**

## 嗚呼、使ってみたい
ML系のサービスを試したいときに困るのが、大量の学習データの用意です。
Web上のどこからか引っ張ってきたり、予め用意されている [サンプルデータ](https://docs.microsoft.com/ja-jp/azure/machine-learning/studio/use-sample-datasets) を使用したり。
いろいろ方法はありますが、やっぱり自分でデータを作って弄って試してみたい。と思うものです。

## 何をするのか①
そこで今回は、例えば株価のような時系列データを手元で生成し、
それを ML Studio に食べさせてみたいと思います。
言わずもがな、時系列データは、画像や文章に比べて圧倒的に生成しやすいです。
如何ようにもできちゃいます。
今回は手軽さを重視して、そんな時系列データを対象にしました。

## 何をするのか②
詳しく後述しますが、10000個の値を持つ時系列データを用意します。
10000日分の株価だと思ってもらえれば、想像に易いかと思います。
そして、**「今日を含む過去20日間の株価から、翌日の株価を予測する」**ことにします。
例えば、「1～20日目の株価を見て、21日目の株価を予測する」という感じです。

## おことわり
ML Studio を一通り使ってみることに重きを置いた記事です。
そのため、**データ生成や疑似トレードのソースコードは割愛しています。**
やっていることは非常に簡単ですので、お好きなプログラム言語[^1]で再現できるはずです。
本質的な部分は、文章で説明しています。

また、筆者は実際の株トレードなどに関してはズブの素人ですので、
言葉の使い方など誤りがあるかもしれません。
それぞれの単語に、深い意味や厳密性は持たせていませんので、ご了承ください。
イメージだけ伝わればOKです。

# 時系列データの準備
学習・テストに使用する時系列データは、
振幅と周期をランダムに変化させた[正弦波](https://ja.wikipedia.org/wiki/%E6%AD%A3%E5%BC%A6%E6%B3%A2)に、ノイズを加えたものとします。
今回は実験なので確率的に異なるものを、手元でいくらでもサンプリングできるようにしておきます。

10000個の値からなる時系列データを、学習用・テスト用の2種類用意しました。

* 学習データ
![training.png](https://qiita-image-store.s3.amazonaws.com/0/112587/1a37322c-07d3-0b70-1a6b-6832c0704216.png)

* テストデータ
![test.png](https://qiita-image-store.s3.amazonaws.com/0/112587/74648bf1-c314-6462-527e-28974558613f.png)

上の2種類のデータは、同じ生成モデルからサンプリングしているので、
値は違えど似たような特徴を有しているはずです。

ML Studio に渡す学習・テストデータは、このグラフのような値そのままでありません。
先述のとおり、
**過去20日分＋予測したい1日分 = 21個の値** を1行として、
1日目から9980日目まで1日ずつシフトして切り取った9980行のCSVデータ[^2]を用います。

# ML Studio を使用した時系列データの学習

では、前準備ができましたので、いよいよ ML Studio を触っていきましょう。
[Azure のサブスクリプション](https://account.azure.com/Subscriptions)は準備できている前提とします。

## Machine Learning Studio ワークスペースの作成
素直に追加します。名前も一旦は適当で。
実験用なので、価格・プランも一番低廉なもので問題ありません。
<img src="https://qiita-image-store.s3.amazonaws.com/0/112587/a00d6c58-be5a-0d81-785f-cac2efe7f5f1.png" width="50%"></img>

プラン、ワークスペース、ストレージの3つが作成されています。
今回は、ワークスペースのみ使用します。
<img src="https://qiita-image-store.s3.amazonaws.com/0/112587/ec534aac-8572-ac64-4276-6892b556240d.png" width="50%"></img>

## ML Studio の起動
作成したワークスペースを開くと、次のような画面が出てきます。
**「Machine Learning Studio の起動」**をクリックすると、文字通り、起動します。
分かりやすいですね。
![screencapture-portal-azure-1512051863124.png](https://qiita-image-store.s3.amazonaws.com/0/112587/0cbd7181-a7d3-1ba0-aff3-066c3c400051.png)

今回は0から実験したいので、「Blank Experiment」を追加しましょう。
![screencapture-japaneast-studio-azureml-net-Home-ViewWorkspaceCached-4f33ac9b949f407e88afba9e0f1d3db0-1512052377293.png](https://qiita-image-store.s3.amazonaws.com/0/112587/05a8ec23-4c30-1f4d-9b32-5b989bd7d08f.png)

お、なんだか楽しそうな画面が出てきましたね！わくわくします。
![screencapture-japaneast-studio-azureml-net-Home-ViewWorkspaceCached-4f33ac9b949f407e88afba9e0f1d3db0-1512052402483.png](https://qiita-image-store.s3.amazonaws.com/0/112587/bd876780-4657-80eb-28e4-53f01281416e.png)

## データセットの追加
先ほど作成した時系列データを ML Studio 上では、データセットという概念として扱います。
データセットに、学習データ、テストデータを追加してみましょう。
CSVファイルをアップロードするだけです。簡単ですね。
![screencapture-japaneast-studio-azureml-net-Home-ViewWorkspaceCached-4f33ac9b949f407e88afba9e0f1d3db0-1512053351367.png](https://qiita-image-store.s3.amazonaws.com/0/112587/fbe313ce-e6a6-5f1a-ab88-5f8a95a05bf7.png)

## 学習フローの定義
### まずは、何より学習データをセット
先ほど追加したデータセットを、ドラッグ＆ドロップで配置します。
GUIでできちゃうなんて素敵。

![screencapture-japaneast-studio-azureml-net-Home-ViewWorkspaceCached-4f33ac9b949f407e88afba9e0f1d3db0-1512053479332.png](https://qiita-image-store.s3.amazonaws.com/0/112587/0cdc0583-8c2b-5adc-bb61-98c3afea3c72.png)

データセットの中身を確認することもできます。
ちゃんと、**col0, col1, col2...** のデータがあるようです。

![screencapture-japaneast-studio-azureml-net-Home-ViewWorkspaceCached-4f33ac9b949f407e88afba9e0f1d3db0-1512054153370.png](https://qiita-image-store.s3.amazonaws.com/0/112587/f10a5b8a-70a7-c72f-79bf-5e3fa667da5a.png)

あれっ！！？？
過去20日分のデータをもとに、翌日1日分の値を予測するので、
カラムは **col0 ～ col20** までの21列になるはずが…。
プログラムのミスで、**col21** という空カラムができてしまっているようです…！

![screencapture-japaneast-studio-azureml-net-Home-ViewWorkspaceCached-4f33ac9b949f407e88afba9e0f1d3db0-1512054127037.png](https://qiita-image-store.s3.amazonaws.com/0/112587/7c0c07f3-89b1-0e4a-60f8-04d91740fb64.png)

### 必要なデータを選ぶ
データセットの中に、不要なデータが混じるケースは往々にしてあります。
そんなときは慌てずに、モジュール**「Select Columns in Dataset」**を使いましょう。
データセット「training.csv」を「Select Columns in Dataset」に流し込みます。

![screencapture-japaneast-studio-azureml-net-Home-ViewWorkspaceCached-4f33ac9b949f407e88afba9e0f1d3db0-1512054220169.png](https://qiita-image-store.s3.amazonaws.com/0/112587/c236014c-4a5e-ac1e-984d-030f88987d1c.png)

モジュールを選択すると、画面右部の Properties からそのモジュールの詳細を設定できます。
モジュール「Select Columns in Dataset」では、学習に使用するカラムを指定できます。

![screencapture-japaneast-studio-azureml-net-Home-ViewWorkspaceCached-4f33ac9b949f407e88afba9e0f1d3db0-1512054244585.png](https://qiita-image-store.s3.amazonaws.com/0/112587/93ad6f13-e470-c48b-ce05-c5b9966f1695.png)

これで、学習に必要なデータの整備ができました。

### 学習フェーズの定義
さて、いよいよ学習モジュールの追加です。といっても、呆気ないほど簡単です。
学習を行うモジュール**「Train Model」**を追加し、学習に使用するアルゴリズムを他モジュールから入力する形で指定します。
アルゴリズムも多数用意されていますが、今回は何も考えずに [Linear Regression（線形回帰）](https://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E5%9B%9E%E5%B8%B0)を使ってみましょう。[^3]

![screencapture-japaneast-studio-azureml-net-Home-ViewWorkspaceCached-4f33ac9b949f407e88afba9e0f1d3db0-1512054516002.png](https://qiita-image-store.s3.amazonaws.com/0/112587/d41630c9-6f96-641f-b078-6b0fdc8d20ca.png)

「Train Model」で、予測したい値（カラム）を指定します。
ここでは、21日目の値を予測したいので、21列目（**col20**）がこれに該当します。

![screencapture-japaneast-studio-azureml-net-Home-ViewWorkspaceCached-4f33ac9b949f407e88afba9e0f1d3db0-1512054605485.png](https://qiita-image-store.s3.amazonaws.com/0/112587/49827952-d86e-3055-f62b-28b84f99b651.png)

### 予測フェーズの定義
モジュール「Train Model」で学習したモデルを使用して、未知のデータを予測してみましょう。
予測にはモジュール**「Score Model」**を使用します。
予測に使用するモデルを「Train Model」から入力し、
予測したい未知のデータをデータセット「test.csv」から入力します。

予測後、「どれくらい上手に予測できたのか」を評価したいので、
モジュール**「Evaluate Model」**に「Score Model」の出力を渡しておきます。

![screencapture-japaneast-studio-azureml-net-Home-ViewWorkspaceCached-4f33ac9b949f407e88afba9e0f1d3db0-1512055603385.png](https://qiita-image-store.s3.amazonaws.com/0/112587/61594d20-3eb5-c148-c2d7-e8e50af596dd.png)

## さあ、学習＆予測を走らせよう！
画面下部の**「Run」**をクリックします。え？これだけ？　…これだけです。
学習フローの上から順に実行されていきます。完了したモジュールに付くグリーンのチェックがかっこいい。
学習データのサイズは 9980行×21列 でしたが、数秒でフローが完了しました。速い。

実は、1つ前の画像が、処理を走らせた直後の様子でした。

予測がどれくらいうまくいったのか、**「Evaluate Model」**を可視化してみましょう。

![screencapture-japaneast-studio-azureml-net-Home-ViewWorkspaceCached-4f33ac9b949f407e88afba9e0f1d3db0-1512055633170.png](https://qiita-image-store.s3.amazonaws.com/0/112587/cf7a3e1e-84e5-1cf2-ef61-fa1d261f40ab.png)

Error Histgram が視覚的に分かりやすいですね。
Error（誤差）が 0.0000047 以下のデータが再瀕ですね。
これは期待できます。

予測したデータを使用して、疑似トレード（シミュレーション）を行いたいので、
モジュール「Score Model」の結果をCSVファイルに出力してみましょう。

**「Convert to CSV」**という分かりやすい名前のモジュールがあるので、これに「Score Model」の結果をびよーんと流し込みます。
あとは、「Convert to CSV」を右クリック → Download でCSVファイルを取得できます。

![screencapture-japaneast-studio-azureml-net-Home-ViewWorkspaceCached-4f33ac9b949f407e88afba9e0f1d3db0-1512055048830.png](https://qiita-image-store.s3.amazonaws.com/0/112587/5be348d2-a38b-ab08-e248-89db0e555184.png)

# AIトレーダー vs 無垢トレーダー
テストデータを対象に、トレードをシミュレートしてみましょう。
ルールは簡単です。
* 翌日の値が「上がる」と予測したら今日「買う」
* 儲け = 実際の翌日の値 - 買った時の値
* 儲けを最大化したい

2名のトレーダーに戦略を与えて、トレードしてもらいましょう。
9980回の長丁場です！がんばって！！

## AIトレーダー

<img src="https://qiita-image-store.s3.amazonaws.com/0/112587/88f12b27-d125-816d-4955-0b152088ad94.png" width="20%"/>

### 戦略
ML Studio で学習して得られた、予測データに従う。
予測データから、**今日の値 ＜ 翌日の値** と分かれば買う。

### 結果
* 勝率：71.91%
* 儲け：<font color="Blue">+2740.34</font>

## 無垢トレーダー

<img src="https://qiita-image-store.s3.amazonaws.com/0/112587/358d410e-4469-fc88-efdd-38f7bbe314ef.png" width="20%"/>

### 戦略
翌日の値が上がるかどうかを $ \frac{1}{2} $ の確率でランダムに決める。神頼み戦法。
**丁と出れば買うし、半と出れば買わない。**

### 結果
* 勝率：49.50%
* 儲け：<font color="Red">-0.69</font>

# まとめと感想

これまで、機械学習の数理的背景ばかりを追っていたので、
最新のMLサービスの使い勝手の簡単さには目からウロコでした。
まだ、GUIで操作する部分にしか触れていません。これだけでも十分に遊べると思いますが、
**自分でコードを書いてより柔軟なモデルを作成することもできるようです。**
ちょっとずつ掘ってみたいですね。

そして、言葉は悪いですが、すごく適当に何も考えずに構成した学習フローでしたが、
AIトレーダーの結果を見て分かる通り、予測データを用いると有意に高い勝率を叩き出しています。

**現実世界のトレードでも、全く同じ手法が通用するかと問われれば、それは否です。**
実際は、背後にさまざまな要因を隠した時系列データであるためです。
今回使用したデータは、ただ正弦波にノイズを加えた程度の**簡単なデータ**であることをご留意ください。

ただ、MLは正弦波の上がり下がりのパターンや、ノイズの特徴を何かしら見つけたのだと考えます。
それが、勝率 **71.91%** という結果に現れています。 

学習データさえ用意できれば、数分で学習と予測ができてしまいます。
この手軽さを少しでも感じていただけたなら、
Advent Calendar 1日目の記事としてお役目を果たせたと思います。
ぜひ皆さんも、遊んでみてください。ではでは。

[^1]: 筆者は Python 2.7系で実装しました。関数分割しても100行未満に収まる程度のボリュームです。
[^2]: 9980行のCSVデータ … あとで気づいたプログラムのミスです。10001日目が無いので9980行目は不正なデータです。記事中では頑なに9980という数字を使用しますが、ご容赦を…。
[^3]: 本来は、適切なアルゴリズムを志ん朝に選ばなければなりません。