読者です 読者をやめる 読者になる 読者になる

Keras の LSTM で時系列の予測がしたい

深層学習で時系列の予測がしたいときとかあると思います。
以下の記事を参考にさせていただきます。
qiita.com

それで時系列データが手元にないので以下のサイトにある日経平均株価の日足をつかいます。
  日経平均株価 1時間足 時系列データ CSVダウンロード
直近1000営業日の値動きをプロットすると以下です。縦軸は学習のためにスケーリング済みです。

f:id:cookie-box:20170409085713p:plain:w700

以下のコードで学習します。参考記事のままです。前日まで10営業日分の株価を入力して当日の株価を予測するというモデルにします。900営業日分のデータで学習し、100営業日分のデータでテストすることにします。

# -*- coding: utf-8 -*-
import numpy
import pandas
import matplotlib.pyplot as plt

from sklearn import preprocessing
from keras.models import Sequential
from keras.layers.core import Dense, Activation
from keras.layers.recurrent import LSTM

# 学習用データを抽出する関数
def _load_data(data, n_prev=10):
  docX, docY = [], []
  for i in range(len(data) - n_prev):
    docX.append(data.iloc[i:(i+n_prev)].as_matrix())
    docY.append(data.iloc[i+n_prev].as_matrix())
  alsX = numpy.array(docX)
  alsY = numpy.array(docY)
  return alsX, alsY

if __name__ == "__main__":
  # 株価データの読み込み
  data = None
  for year in range(2007, 2018):
    data_ = pandas.read_csv('indices_I101_1d_' + str(year) +  '.csv')
    data = data_ if (data is None) else pandas.concat([data, data_])
  data.columns = ['date', 'open', 'high', 'low', 'close']
  data['date'] = pandas.to_datetime(data['date'], format='%Y-%m-%d')
  data['close'] = preprocessing.scale(data['close'])
  data = data.sort_values(by='date')
  data = data.reset_index(drop=True)
  data = data.loc[:, ['date', 'close']]
  data = data[1516:2515]

  # plt.plot(data['date'], data['close'])
  # plt.show()

  # 学習の設定
  length_of_sequences = 10
  in_out_neurons = 1
  hidden_neurons = 300

  # データ準備
  X_train, y_train = _load_data(data[['close']].iloc[0:900],    length_of_sequences)
  X_test,  y_test  = _load_data(data[['close']].iloc[900:1000], length_of_sequences)

  # ニューラルネットの定義
  model = Sequential()
  model.add(LSTM(hidden_neurons, \
            batch_input_shape=(None, length_of_sequences, in_out_neurons), \
            return_sequences=False))
  model.add(Dense(in_out_neurons))
  model.add(Activation("linear"))
  model.compile(loss="mean_squared_error", optimizer="rmsprop")

  # 学習
  model.fit(X_train, y_train, batch_size=100, nb_epoch=100, validation_split=0.05)

  # テスト結果表示
  predicted = model.predict(X_test)
  result = pandas.DataFrame(predicted)
  result.columns = ['predict']
  result['actual'] = y_test
  result.plot()
  plt.show()

テスト結果は以下です。当日の株価を予測するというか、前日をなぞっているだけですね。しかもなんかオフセットが付いているし。こんなの予測をしているといえない。知ってた。

f:id:cookie-box:20170409084531p:plain:w720

ネットワークに予測性能があるか確認するのに、もう少し「直前のN点から次の1点を予測できそう」な時系列をつかいたいです。そこで、R 組み込みの UKgas をつかいます。以下のようなデータです。四半期毎のデータなので周期性をもちます(冬はガス消費量が多く、夏は少ない)。
f:id:cookie-box:20170303235217p:plain:w700

以下の箇所以外さっきと同じコードで学習します。さっきは「直前までの10点から次の1点を予測」にしましたが、今回は四半期毎のデータなのでなんとなく4の倍数で12にします。UKgas は107点ありますが、最初の90点を学習につかい、最後の17点が予測できるかをテストします。

  length_of_sequences = 12
  in_out_neurons = 1
  hidden_neurons = 300

  X_train, y_train = _load_data(data[['gas']].iloc[0:90],    length_of_sequences)
  X_test,  y_test  = _load_data(data[['gas']].iloc[78:107], length_of_sequences)

  model.fit(X_train, y_train, batch_size=30, nb_epoch=100, validation_split=0.05)

テスト結果は以下です。予測結果も周期性をもっており、前回をなぞるだけではなく予測めいたことをしているようにはみえます。よかった。

f:id:cookie-box:20170409092832p:plain:w720