Python
DeepLearning
TensorFlow

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

More than 3 years have 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