今日も窓辺でプログラム

外資系企業勤めのエンジニアが勉強した内容をまとめておくブログ

日経平均の終値が前日より上がるか下がるかをTensorFlowで予測する(2.5)

今回やること

前回まで使用していたプログラムがYahoo!Financeの仕様変更で使えなくなっていたので、書き直します。
前回までの記事はこちら:
日経平均の終値が前日より上がるか下がるかをTensorFlowで予測する(1) - 今日も窓辺でプログラム
日経平均の終値が前日より上がるか下がるかをTensorFlowで予測する(2) - 今日も窓辺でプログラム

今回書き直す内容は以下の通りです。

  • データソースをYahoo!Financeからほげほげに変更する
  • ついでに、TensorFlowを使用している部分ををInference, Loss, Trainingというコード分割で書き直す

FTSEとSTIのデータがとってこれなくなった

久しぶりに以前書いた日経平均予想のスクリプトを走らせると、FTSEとSTIのデータがとってこれなくなっていました。
原因はYahoo!Financeの仕様変更のようで、例えば、日経のデータは"Download data"というボタンがあるけれど、
^N225 Historical Prices | Nikkei 225 Stock - Yahoo Finance

FTSEからはダウンロードするリンクはなくなってしまっています。
^FTSE : Summary for FTSE 100 - Yahoo Finance

Quandlを使ってみる

前回はちょっとあまりにもデータ収集部分を適当に書きすぎたので、今回はQuandlというサイトを使用してもう少し真面目に書いてみたいと思います。
Quandl Financial and Economic Data

このQuandlというサイトは、世界の様々なデータにアクセスできるAPIを提供しているさいとで、日経平均のような株に関連するデータもたくさん提供されています。
データは世界中の世界中の様々な機関が提供しており、前回まで使用していたYahoo!Financeもデータ提供をしているようです。

Python向けのAPIが提供されているので、まずはそれをインストール。

pip install quandl

すると、これだけのプログラムで、データがとってこれます!

import quandl

quandl.ApiConfig.api_key = "<API Key>"
quandl.ApiConfig.api_version = "2015-04-09"

data = quandl.get("YAHOO/INDEX_N225")
print(data.tail())

データは前回と同じpandasで得られているので、data.tail()とかdata.describe()とか前回と同じように操作できます。
quandl.getの引数部分に、データソースと欲しいデータを文字列にして渡してあげると、どんなデータでも同じ方法で簡単に取得することができます。素晴らしい!

パラメータも渡すことができて、例えば今年のデータだけほしい場合は次のようにリクエストを投げます。

quandl.get("YAHOO/INDEX_N225", start_date="2016-01-01")

このAPIを使用して書き直してみたコードをこちらにおいておきます。
pred225/stockdata.py at a37126479e6fb73d114220ff574026842a27e23c · kanoh-k/pred225 · GitHub

結局FTSEとIXICはキーが正しくないといわれて取得できませんでした。有料のデータソースだったらいくつかデータが取れそうなものがあるのですが、今回はとりあえずこの2つは使用せずに進めることにします。。

メインロジックの書き直し

前回まではチュートリアルのコードをそのままコピペしていて、コード分割がうまくできていなかったので、チュートリアルのBuild the graphのページにある内容に従ってコードを分割してみます。
TensorFlow Mechanics 101  |  TensorFlow

日本語で上記ページの内容を解説してある記事もあります。
TensorFlowのコード分割の考え方 - Qiita

簡単にまとめると、下記の3つの部分に分割することが推奨されています。

  1. inference() - 実際に推論を行うニューラルネット
  2. loss() - ニューラルネットの損失関数
  3. training() - 損失関数を最適化する部分

ソースコード全体はGitHubにあげておくので、ここでは該当部分のみを見ていきます。
実際にこれらの関数をどのように使用するかは、サンプルコードのほうを参照していただければと思います。
全体のソース
pred225/eval.py at a37126479e6fb73d114220ff574026842a27e23c · kanoh-k/pred225 · GitHub

inference()

まずはネットワークを定義する部分です。特徴量データのplaceholderなどを受け取って、ネットワークを構築して返します。

def inference_no_hidden(feature_data, num_predictors, num_classes):
    weights = tf.Variable(tf.truncated_normal([num_predictors, num_classes], stddev=0.0001))
    biases = tf.Variable(tf.ones([num_classes]))

    model = tf.nn.softmax(tf.matmul(feature_data, weights) + biases)
    return model

loss()

次は損失関数を定義する部分です。前回と同様、クロスエントロピーを使用します。

def loss(model, labels):
    cost = -tf.reduce_sum(labels*tf.log(model))
    return cost

training

次は最適化の部分です。こちらも前回同様Adam Optimizerを適用しているだけです。

def training(cost, learning_rate=0.0001):
    training_op = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
    return training_op

走らせてみる

新しいソースコードで書き直してみたところ、隠れ層なしの場合(つまり、inference_no_hidden()を使った場合)
Precision = 0.6165413533834586
Recall = 0.82
F1 Score = 0.7038626609442059
Accuracy = 0.6532663316582915

隠れ層あり(=intefence_two_hidden)の場合、
Precision = 0.6666666666666666
Recall = 0.7
F1 Score = 0.6829268292682926
Accuracy = 0.6733668341708543

という結果が得られました。前回までとは使っているデータソースやその期間が異なっているので、数値も異なるものとなっています。
前回隠れ層なしのほうが良い精度が出た気がするんですが、あれは何だったんでしょう…。

(2016/08/31追記:プログラムのデータを作成する部分にバグがあり、この数値は正しくないものであることが判明しました。手法や記事で直接言及した部分の実装は問題ないはずです。)
(2016/9/20追記:正しい数値での記事を投稿しました(クリックで記事へ移動)

次回予告

実は、以前まではさくらVPSに入れたUbuntuでTensorflowを走らせていたのですが、今回からはWindows 10の Bash on Windowsを使って走らせています。
これによって、前回までは私の環境では使えなかったTensorBoardが使えるようになった(はず)なので、次回はTensorBoardを使ってネットワークが最適化されている様子を観察してみたいと思います。



次回記事:
TensorBoardで学習の過程を可視化する ~株価予測(3)~ - 今日も窓辺でプログラム