ディープラーニング(TensorFlow)を使用した株価予想 ~その2~

  • 535
    Like
  • 12
    Comment
More than 1 year has passed since last update.

前回の続き。
ディープラーニングのフレームワークであるTensorFlowを使用して株価を予想するぞ~、というお話です。ちなみに前回は完全に失敗でした。
前回のコメントで、tawagoさんから「Googleが同じようなことしている」という情報をいただいたので、そちらをコピ・・・インスパイアしてみました。

前回との相違点

前回は、「数日分の日経平均を使用して、次の日の日経平均が上がるか、下がるか、変わらないか(3択)を予想する」ものでした。
Googleのデモでは、「数日分の世界中の株価指数(ダウ、日経平均、FTSE100、DAXなど)を使用して、次の日のS&Pが上がるか下がるか(2択)を予想する」という内容でした。
ということで、下記が前回からの主な変更点となります。
- 「上がるか」「下がるか」の2択
- 日経平均だけでなく、他国の株価指数も使用
- 隠れ層x2、ユニット数は50,25
予想するのは前回と同じく、次の日の日経平均です。

Googleのデモの詳細はこちらの動画から。(英語)

環境

TensorFlow 0.7
Ubuntu 14.04
Python 2.7
AWS EC2 micro instance

実装

準備

Quandlというサイトから、データがダウンロードできるようです。
しかし、掲載されているデータが膨大過ぎて、どれをダウンロードしたら良いのか分からないという問題が発生したため、今回は日経、ダウ、香港ハンセン、ドイツの4つのみ利用することにします。Googleのデモでは8つくらい使用していました。

落としてきたデータは一つの表にまとめてCSVで保存します。特にスクリプトとかありません。ExcelのVLOOKUP関数とか使った手作業でやりました。出来る人ならDBに入れて上手く扱うのでしょうが・・・

ラベル

今回は「上がる」か「下がる」かの2択なので、正解のフラグは下記のような感じ。

if array_base[idx][3] > array_base[idx+1][3]:
  y_flg_array.append([1., 0.])
  up += 1
else:
  y_flg_array.append([0., 1.])
  down += 1

サンプル全体としては、
上がる:50.6%
下がる:49.4%
となりました。

グラフ作成

グラフはほぼGoogleのコードを真似ています。
隠れ層の数やユニット数もGoogleのコードのままです。
ドロップアウトは無かったかもしれないですが。

NUM_HIDDEN1 = 50
NUM_HIDDEN2 = 25
def inference(x_ph, keep_prob):

  with tf.name_scope('hidden1'):
    weights = tf.Variable(tf.truncated_normal([data_num * price_num, NUM_HIDDEN1], stddev=stddev), name='weights')
    biases = tf.Variable(tf.zeros([NUM_HIDDEN1]), name='biases')
    hidden1 = tf.nn.relu(tf.matmul(x_ph, weights) + biases)

  with tf.name_scope('hidden2'):
    weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN1, NUM_HIDDEN2], stddev=stddev), name='weights')
    biases = tf.Variable(tf.zeros([NUM_HIDDEN2]), name='biases')
    hidden2 = tf.nn.relu(tf.matmul(hidden1, weights) + biases)

  #DropOut
  dropout = tf.nn.dropout(hidden2, keep_prob)

  with tf.name_scope('softmax'):
    weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN2, 2], stddev=stddev), name='weights')
    biases = tf.Variable(tf.zeros([2]), name='biases')
    y = tf.nn.softmax(tf.matmul(dropout, weights) + biases)

  return y

損失

前回書き忘れた損失は下記のように定義。
前回と変わっていませんが、こちらもGoogleさんと同じです。

def loss(y, target):
  return -tf.reduce_sum(target * tf.log(y))

最適化

最適化は前回と変わらず。

def optimize(loss):
  optimizer = tf.train.AdamOptimizer(learning_rate)
  train_step = optimizer.minimize(loss)
  return train_step

訓練

訓練も何一つ前回と変わらず。

def training(sess, train_step, loss, x_train_array, y_flg_train_array):

  summary_op = tf.merge_all_summaries()
  init = tf.initialize_all_variables()
  sess.run(init)

  summary_writer = tf.train.SummaryWriter(LOG_DIR, graph_def=sess.graph_def)

  for i in range(int(len(x_train_array) / bach_size)):
    batch_xs = getBachArray(x_train_array, i * bach_size, bach_size)
    batch_ys = getBachArray(y_flg_train_array, i * bach_size, bach_size)
    sess.run(train_step, feed_dict={x_ph: batch_xs, y_ph: batch_ys, keep_prob: 0.8})
    ce = sess.run(loss, feed_dict={x_ph: batch_xs, y_ph: batch_ys, keep_prob: 1.0})

    summary_str = sess.run(summary_op, feed_dict={x_ph: batch_xs, y_ph: batch_ys, keep_prob: 1.0})
    summary_writer.add_summary(summary_str, i)

評価

評価も前回と変わらず。

correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_ph, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

print(sess.run(accuracy, feed_dict={x_ph: x_test_array, y_ph: y_flg_test_array, keep_prob: 1.0}))

結果~その1~

上記の結果、精度は

0.50295

・・・ダメやん。

修正

入力として、各国の株価指数をそのままぶっこんでましたが、ここを少し修正。入力は「その株価指数が前日と比べてどれくらい上下したか」をいれることにしました。(定かではないが、ビデオ内でGoogleもそうやっているように見えた)
コードにすると、こんな感じ。(分かりにくいかもしれませんが)

tmp_array = []
for j in xrange(idx+1, idx + data_num + 1):
  for row, sprice in enumerate(array_base[j]):
    tmp_array.append(sprice)

x_array.append(tmp_array)

上記を、下のように変更。

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

x_array.append(tmp_array)

結果~その2~

0.63185

なんとか意味のある数字になったもよう。63%で「上がるか」「下がるか」を予想できているので、当てずっぽうよりかは良い結果が出せていると言えます。
というわけで、一応成功とします(^_^;)
Googleのデモだと72%程度の精度になっていたと思いますが、まぁこっちは使用している株価指数の数も少ないし、こんなものだと思います。

考察

  • 入力は「独立した数字群」より、「全体として意味がある数字群」とした方が良い結果が出るのかもしれない。
  • 前回どうでもいいのかと思っていたtf.truncated_normal()のstddev指定が割と大事。デフォルトのままだと発散しやすいので0.001とかを指定しています。発散しているようなら調整した方が良いパラメータのようです。
  • Googleの指定している隠れ層のユニット数とか結構適当に見える。今回、50と25だけど、最初のユニット数は入力の2倍くらい見ておけばいいのか?(よく分からない)
  • Googleのデモ同様にもっと多くの株価指数を入れたり、為替などのデータを入れるともっと精度が上がるかも。

所感

  • とりあえずそれっぽくなって良かった!
  • TensorFlowはデータが多少変わっても、訓練部分など変えなくて良い部分が多いので、一回テンプレートのようなものを作ってしまえばコーディングが楽。どっちかというと入力データの加工の方が面倒。
  • 上記理由で、数字はなるべく定数化しておいた方が後々楽。

ところで・・・

どなたか、為替の5, 15, 30分足データとかダウンロードできるサイトをご存知の方いましたら教えてください。m(__)m