517
523

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-03-26

前回の続き。
ディープラーニングのフレームワークである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

517
523
12

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
517
523

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?