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