LSTM、GRUモデルを用いた株式相場予想

# はじめに

機械学習を用いて、S&P500の株式相場予想を行なった。

また、参考サイトはこちら。

https://qiita.com/Umaremin/items/4317fb88299995e54e5f

repositoryはこちら。
https://github.com/sugiyama404/forecast_sp500/blob/main/forecast_sp500_lstm_gru.ipynb

# インポートと前処理

```python
import numpy as np
import pandas as pd
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,GRU

from keras.optimizers import Adam
from keras.callbacks import EarlyStopping
from sklearn.model_selection import train_test_split
from google.colab import drive
import time

drive.mount('/content/drive/')
nov_dir = 'Colab Notebooks/dataset/'
nov_path = '/content/drive/My Drive/' + nov_dir + 'data_csv_sp500.csv'

df = pd.read_csv(nov_path)
df['Date'] = pd.to_datetime(df['Date'], format = '%Y-%m-%d')
df['SP500'] = preprocessing.scale(df['SP500'])

print(df.shape)

maxlen = 10
n_sample = len(df) - maxlen
X, Y = [], []
for i in range(len(df) - maxlen):
    X.append(df[['SP500']].iloc[i:(i+maxlen)].values)
    Y.append(df[['SP500']].iloc[i+maxlen].values)
X=np.array(X)
Y=np.array(Y)

print(X.shape)
print(Y.shape)

N_train = int(len(df) * 0.8)
N_test = len(df) - N_train
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=N_test, shuffle = False) 
```

```console
(1768, 2)
(1758, 10, 1)
(1758, 1)
```

```python
def stopwatch(end_time,start_time):
  elapsed_time = int(end_time - start_time)

  elapsed_hour = elapsed_time // 3600
  elapsed_minute = (elapsed_time % 3600) // 60
  elapsed_second = (elapsed_time % 3600 % 60)

  mozi = str(elapsed_hour).zfill(2) + ":" + str(elapsed_minute).zfill(2) + ":" + str(elapsed_second).zfill(2)
  return mozi
```


# モデル構築

```python
n_in = 1
n_mid = 20
n_out = 1
batch_size = 8
opt = Adam(lr=0.001, beta_1=0.9, beta_2=0.999)

model_lstm = Sequential()
model_lstm.add(LSTM(n_mid,batch_input_shape=(None, maxlen, n_in),return_sequences=False))
model_lstm.add(Dense(n_in, kernel_initializer='random_uniform'))
model_lstm.add(Activation("linear"))
model_lstm.compile(loss = "mean_squared_error", optimizer=opt)
print(model_lstm.summary())

model_gru = Sequential()
model_gru.add(GRU(n_mid,batch_input_shape=(None, maxlen, n_in),return_sequences=False))
model_gru.add(Dense(n_in, kernel_initializer='random_uniform'))
model_gru.add(Activation("linear"))
model_gru.compile(loss = "mean_squared_error", optimizer=opt)
print(model_gru.summary())
```

```console
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
lstm (LSTM)                  (None, 20)                1760      
_________________________________________________________________
dense (Dense)                (None, 1)                 21        
_________________________________________________________________
activation (Activation)      (None, 1)                 0         
=================================================================
Total params: 1,781
Trainable params: 1,781
Non-trainable params: 0
_________________________________________________________________
None
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
gru (GRU)                    (None, 20)                1380      
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 21        
_________________________________________________________________
activation_1 (Activation)    (None, 1)                 0         
=================================================================
Total params: 1,401
Trainable params: 1,401
Non-trainable params: 0
_________________________________________________________________
None
```

# 学習

```python
epochs = 100

start_time = time.time()
hist_lstm = model_lstm.fit(X_train, y_train, batch_size=batch_size, epochs=epochs,verbose=0)
print("学習時間 LSTM : ", stopwatch(time.time(),start_time))

start_time = time.time()
hist_gru = model_gru.fit(X_train, y_train, batch_size=batch_size, epochs=epochs,verbose=0)
print("学習時間 GRU : ", stopwatch(time.time(),start_time))
```

```console
学習時間 LSTM :  00:01:02
学習時間 GRU :  00:01:08
```

# 損失関数

```python
nov_dir2 = 'Colab Notebooks/workspace/export/'

loss_lstm = hist_lstm.history['loss']
epochs_lstm = len(loss_lstm)

loss_gru = hist_gru.history['loss']
epochs_gru = len(loss_gru)

plt.plot(range(epochs_lstm), loss_lstm, label="loss_lstm", color='tab:orange')
plt.plot(range(epochs_gru), loss_gru, label="loss_gru", color='tab:green')
plt.title('Loss Function')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
nov_path = '/content/drive/My Drive/' + nov_dir2 + 'fc_sp500_lossfunc.png'

plt.savefig(nov_path)
plt.show()
plt.close('all')
```

![fc_sp500_lossfunc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/fadd8e8d-d09e-be71-4973-85be79b2a6e3.png)


# 訓練結果

```python
predicted_gru = model_gru.predict(X_train)
predicted_lstm = model_lstm.predict(X_train)
result = pd.DataFrame(predicted_gru)
result.columns = ['forcast_gru']
result['actual'] = y_train
result['forcast_lstm'] = predicted_lstm
result = result.reindex(columns=['actual', 'forcast_lstm', 'forcast_gru'])

plt.figure()
result.plot()
plt.title('Stock Price Prediction (training)')
plt.xlabel('Days')
plt.ylabel('Open Price (preprocessing)')


nov_path = '/content/drive/My Drive/' + nov_dir2 + 'fc_sp500_training.png'
plt.savefig(nov_path)
plt.show()
plt.close('all')


predicted_gru = model_gru.predict(X_test)
predicted_lstm = model_lstm.predict(X_test)
result = pd.DataFrame(predicted_gru)
result.columns = ['forecast_gru']
result['actual'] = y_test
result['forecast_lstm'] = predicted_lstm
result = result.reindex(columns=['actual', 'forecast_lstm', 'forecast_gru'])

plt.figure()
result.plot()
plt.title('Stock Price Prediction (forecast)')
plt.xlabel('Days')
plt.ylabel('Open Price (preprocessing)')

nov_path = '/content/drive/My Drive/' + nov_dir2 + 'fc_sp500_forecast.png'
plt.savefig(nov_path)
plt.show()
plt.close('all')
```

![fc_sp500_training.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/c7a3ecda-2c1e-5e5b-ef50-3ba9f6d1d688.png)

![fc_sp500_forecast.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/49a9958c-bca9-5fbc-7736-c04858db5fe0.png)