ディープラーニング（TensorFlow）を使用した株価予想

なぜかあまりやっている人を見ない、ディープラーニングを使用した株価の予想をしてみます。
ディープラーニング、Pythonともに初心者です。ライブラリ、実装方法、理論等は殆ど分かっておりません。ツッコミ等お待ちしています。

##目標
- 数日分の株価データを使用して、翌日の日経平均株価が「上がる」か「下がる」か「変わらず」かを予想します。（分類）

##概要
- 「上がった」か「下がった」か「変わらず」だったかの判断には翌日の終値をベースに判断。
- 入力データは数日前から前日までの「始値」「高値」「安値」「終値」を使用。
- 隠れ層は4つ。
- 入力として上記過去数日分の株価をぶっこんでトレーニングするだけです。

##環境
TensorFlow 0.7
Ubuntu 14.04
Python 2.7
AWS EC2 micro instance

##内容
###準備
可能な限りの日経平均のデータを用意します。今回は[Yahooファイナンス](http://stocks.finance.yahoo.co.jp/stocks/detail/?code=998407.o)のデータを使用しました。

###実装
日経平均はテキストにしておきます。（毎回取りに行くと面倒なので）
今回は10日分のデータを見て、翌日の株価を予想することにします。
また、翌日の終値が、前日の終値より0.5%以上ならば「上がった」、0.5%以下ならば「下がった」、それ以外ならば「変わらず」としました。この数字の理由は、ちょうどこの3つが33%程度になるためです。

```
if array_base[idx][3] > (array_base[idx+1][3] * (1.0+flg_range)):
  y_flg_array.append([1., 0., 0.])
  up += 1
elif array_base[idx][3] < (array_base[idx+1][3] * (1.0-flg_range)):
  y_flg_array.append([0., 0., 1.])
  down += 1
else:
  y_flg_array.append([0., 1., 0.])
  keep += 1
```
データ全体としての割合は下記の通り。
上がった：33.9%
下がった：32.7%
変わらず：33.4%

###グラフ作成
コードはこんな感じ。コピペで若干スパゲッティですが、まぁ見やすいのではないでしょうか。（という言い訳）

```
def inference(x_ph, keep_prob):

  with tf.name_scope('hidden1'):
    weights = tf.Variable(tf.truncated_normal([data_num * 4, NUM_HIDDEN1]), name='weights')
    biases = tf.Variable(tf.zeros([NUM_HIDDEN1]), name='biases')
    hidden1 = tf.nn.sigmoid(tf.matmul(x_ph, weights) + biases)
  
  with tf.name_scope('hidden2'):
    weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN1, NUM_HIDDEN2]), name='weights')
    biases = tf.Variable(tf.zeros([NUM_HIDDEN2]), name='biases')
    hidden2 = tf.nn.sigmoid(tf.matmul(hidden1, weights) + biases)
  
  with tf.name_scope('hidden3'):
    weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN2, NUM_HIDDEN3]), name='weights')
    biases = tf.Variable(tf.zeros([NUM_HIDDEN3]), name='biases')
    hidden3 = tf.nn.sigmoid(tf.matmul(hidden2, weights) + biases)
  
  with tf.name_scope('hidden4'):
    weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN3, NUM_HIDDEN4]), name='weights')
    biases = tf.Variable(tf.zeros([NUM_HIDDEN4]), name='biases')
    hidden4 = tf.nn.sigmoid(tf.matmul(hidden3, weights) + biases)
  
  #DropOut
  dropout = tf.nn.dropout(hidden4, keep_prob)
  
  with tf.name_scope('softmax'):
    weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN4, 3]), name='weights')
    biases = tf.Variable(tf.zeros([3]), name='biases')
    y = tf.nn.softmax(tf.matmul(dropout, weights) + biases)
  
  return y
```
x_phが前日までの株価データが入ったプレースホルダ。[1日前の終値, 1日前の始値, 1日前の高値, 1日前の安値, 2日前の終値, ...]と言った具合にデータが入っています。
なお、隠れ層のユニット数は100, 50, 30, 10です。つまり、下記で定義しています。

```
# DEFINITION
NUM_HIDDEN1 = 100
NUM_HIDDEN2 = 50
NUM_HIDDEN3 = 30
NUM_HIDDEN4 = 10
```
ちなみにこのユニット数と層数は適当です。多い方がいいんじゃね？くらいのつもりで決めました。
これらの数を決める指針等あるなら教えていただけると幸いですm(__)m

###最適化
最適化はADAMを使用しています。詳しくは知りませんが、経験上、勾配降下法（GradientDescentOptimizer）より発散し辛いイメージ。

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

###訓練
訓練は下記のような感じ。バッチサイズは100にしました。大きすぎるとコケます。（メモリ不足で。ケチらなければ大丈夫です）

```
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})

    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}))
```

##結果
TensorBoardで見てみると、下記のように収束しているように見える。
![nikkei.jpg](https://qiita-image-store.s3.amazonaws.com/0/117826/6bddcbc6-d22e-1557-fded-57ec654ab58b.jpeg)


が、正答率を見てみると、

```
0.3375
```
惨敗。 :scream: 
前述したとおり、各カテゴリ（上がった、下がった、変わらず）の確率が概ね33%なので、当てずっぽうと同じという結果になりました。(笑)

##考察
今回の失敗の原因について、原因と考えられるのは下記の通り。
- モデルの構築が不十分？（アドバイスあればお願いします）
- そもそも前日までの株価は翌日の株価に影響を与えない？
- 日経平均は株価の平均なので、そもそもテクニカル的な要素は関係しない？

なお、入力に使う日数、隠れ層の数、ユニット数、活性化関数等を変更して色々試してみましたが、特に結果に変化はありませんでした。 :sob: 

##所感
行列計算とかディープラーニングとかあまり詳しくありませんが、概要がなんとなく分かってれば、TensorFlowを使ってなんとなくそれらしいことが出来るっぽい！ :satisfied: 

##参考にしたサイト、ページ、文献
[公式チュートリアル](https://www.tensorflow.org/versions/r0.7/tutorials/index.html)
[TensorFlow でポケモンの名前から種族値とタイプを予測させる遊び](http://qiita.com/shuhei_f/items/01a08bf23ba24076ac08)
[深層学習 (機械学習プロフェッショナルシリーズ)](http://www.amazon.co.jp/%E6%B7%B1%E5%B1%A4%E5%AD%A6%E7%BF%92-%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%83%97%E3%83%AD%E3%83%95%E3%82%A7%E3%83%83%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E5%B2%A1%E8%B0%B7-%E8%B2%B4%E4%B9%8B/dp/4061529021)