GRU(门控循环单元)实现股票预测

GRU实现股票预测

  • 1、GRU(门控循环单元)
    • 1.1 GRU原理
    • 1.2 Tensorflow2描述GRU层
    • 1.3 GRU股票预测
      • 1.3.1 数据源
      • 1.3.2 代码实现

1、GRU(门控循环单元)

GRU 由 Cho 等人于 2014 年提出,优化 LSTM 结构。

1.1 GRU原理

  门控循环单元(Gated Recurrent Unit,GRU)是 LSTM 的一种变体,将 LSTM 中遗忘门与输入门合二为一为更新门,模型比 LSTM 模型更简单。
GRU(门控循环单元)实现股票预测_第1张图片
  如上图所示,GRU 使记忆体 h t h_t ht融合了长期记忆和短期记忆。 h t h_t ht包含了过去信息 h t − 1 h_{t-1} ht1和现在信息(候选隐藏层) h t h_t ht,由更新门 z t z_t zt分配重要性:
  记忆体 h t = ( 1 − z t ) ∗ h t − 1 + z t ∗ h t ~ h_t=(1-z_t)*h_{t-1}+z_t*\widetilde{h_t} ht=(1zt)ht1+ztht
  现在信息是过去信息 h t − 1 h_{t-1} ht1过重置门 r t r_t rt与当前输入 x t x_t xt共同决定的:
  候选隐藏层 h t ~ = t a n h ( W . [ r t ∗ h t − 1 , x t ] ) \widetilde{h_t}=tanh(W.[r_t*h_{t-1},x_t]) ht =tanh(W.[rtht1,xt])
  更新门和重置门的取值范围也是 0 到 1 之间:
  更新门 z t = σ ( W z . [ h t − 1 , x t ] ) z_t=\sigma(W_z.[h_{t-1},x_t]) zt=σ(Wz.[ht1,xt])
  重置门 r t = σ ( W r . [ h t − 1 , x t ] ) r_t=\sigma(W_r.[h_{t-1},x_t]) rt=σ(Wr.[ht1,xt])

GRU(门控循环单元)实现股票预测_第2张图片

1.2 Tensorflow2描述GRU层

tf.keras.layers.GRU(
神经元个数,
return_sequences=是否返回输出
)

  return_sequences=True 各时间步输出ht
  return_sequences=False 仅最后时间步输出ht(默认)
  例如:

model = tf.keras.Sequential([
    GRU(80, return_sequences=True),
    Dropout(0.2),
    GRU(100),
    Dropout(0.2),
    Dense(1)
])

1.3 GRU股票预测

1.3.1 数据源

  SH600519.csv 是用 tushare 模块下载的 SH600519 贵州茅台的日 k 线数据,本次例子中只用它的 C 列数据(如图 所示):
  用连续 60 天的开盘价,预测第 61 天的开盘价。
GRU(门控循环单元)实现股票预测_第3张图片
GRU(门控循环单元)实现股票预测_第4张图片

1.3.2 代码实现

import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Dropout, Dense, GRU
import matplotlib.pyplot as plt
import os
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error, mean_absolute_error
import math

maotai = pd.read_csv('./SH600519.csv')  # 读取股票文件

training_set = maotai.iloc[0:2426 - 300, 2:3].values  # 前(2426-300=2126)天的开盘价作为训练集,表格从0开始计数,2:3 是提取[2:3)列,前闭后开,故提取出C列开盘价
test_set = maotai.iloc[2426 - 300:, 2:3].values  # 后300天的开盘价作为测试集

# 归一化
sc = MinMaxScaler(feature_range=(0, 1))  # 定义归一化:归一化到(0,1)之间
training_set_scaled = sc.fit_transform(training_set)  # 求得训练集的最大值,最小值这些训练集固有的属性,并在训练集上进行归一化
test_set = sc.transform(test_set)  # 利用训练集的属性对测试集进行归一化

x_train = []
y_train = []

x_test = []
y_test = []

# 测试集:csv表格中前2426-300=2126天数据
# 利用for循环,遍历整个训练集,提取训练集中连续60天的开盘价作为输入特征x_train,第61天的数据作为标签,for循环共构建2426-300-60=2066组数据。
for i in range(60, len(training_set_scaled)):
    x_train.append(training_set_scaled[i - 60:i, 0])
    y_train.append(training_set_scaled[i, 0])
# 对训练集进行打乱
np.random.seed(7)
np.random.shuffle(x_train)
np.random.seed(7)
np.random.shuffle(y_train)
tf.random.set_seed(7)
# 将训练集由list格式变为array格式
x_train, y_train = np.array(x_train), np.array(y_train)

# 使x_train符合RNN输入要求:[送入样本数, 循环核时间展开步数, 每个时间步输入特征个数]。
# 此处整个数据集送入,送入样本数为x_train.shape[0]即2066组数据;输入60个开盘价,预测出第61天的开盘价,循环核时间展开步数为60; 每个时间步送入的特征是某一天的开盘价,只有1个数据,故每个时间步输入特征个数为1
x_train = np.reshape(x_train, (x_train.shape[0], 60, 1))
# 测试集:csv表格中后300天数据
# 利用for循环,遍历整个测试集,提取测试集中连续60天的开盘价作为输入特征x_train,第61天的数据作为标签,for循环共构建300-60=240组数据。
for i in range(60, len(test_set)):
    x_test.append(test_set[i - 60:i, 0])
    y_test.append(test_set[i, 0])
# 测试集变array并reshape为符合RNN输入要求:[送入样本数, 循环核时间展开步数, 每个时间步输入特征个数]
x_test, y_test = np.array(x_test), np.array(y_test)
x_test = np.reshape(x_test, (x_test.shape[0], 60, 1))

model = tf.keras.Sequential([
    GRU(80, return_sequences=True),
    Dropout(0.2),
    GRU(100),
    Dropout(0.2),
    Dense(1)
])

model.compile(optimizer=tf.keras.optimizers.Adam(0.001),
              loss='mean_squared_error')  # 损失函数用均方误差
# 该应用只观测loss数值,不观测准确率,所以删去metrics选项,一会在每个epoch迭代显示时只显示loss值

checkpoint_save_path = "./checkpoint/stock.ckpt"

if os.path.exists(checkpoint_save_path + '.index'):
    print('-------------load the model-----------------')
    model.load_weights(checkpoint_save_path)

cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,
                                                 save_weights_only=True,
                                                 save_best_only=True,
                                                 monitor='val_loss')

history = model.fit(x_train, y_train, batch_size=64, epochs=50, validation_data=(x_test, y_test), validation_freq=1,
                    callbacks=[cp_callback])

model.summary()

file = open('./weights.txt', 'w')  # 参数提取
for v in model.trainable_variables:
    file.write(str(v.name) + '\n')
    file.write(str(v.shape) + '\n')
    file.write(str(v.numpy()) + '\n')
file.close()

loss = history.history['loss']
val_loss = history.history['val_loss']

plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.title('Training and Validation Loss')
plt.legend()
plt.show()

################## predict ######################
# 测试集输入模型进行预测
predicted_stock_price = model.predict(x_test)
# 对预测数据还原---从(0,1)反归一化到原始范围
predicted_stock_price = sc.inverse_transform(predicted_stock_price)
# 对真实数据还原---从(0,1)反归一化到原始范围
real_stock_price = sc.inverse_transform(test_set[60:])
# 画出真实数据和预测数据的对比曲线
plt.plot(real_stock_price, color='red', label='MaoTai Stock Price')
plt.plot(predicted_stock_price, color='blue', label='Predicted MaoTai Stock Price')
plt.title('MaoTai Stock Price Prediction')
plt.xlabel('Time')
plt.ylabel('MaoTai Stock Price')
plt.legend()
plt.show()

##########evaluate##############
# calculate MSE 均方误差 ---> E[(预测值-真实值)^2] (预测值减真实值求平方后求均值)
mse = mean_squared_error(predicted_stock_price, real_stock_price)
# calculate RMSE 均方根误差--->sqrt[MSE]    (对均方误差开方)
rmse = math.sqrt(mean_squared_error(predicted_stock_price, real_stock_price))
# calculate MAE 平均绝对误差----->E[|预测值-真实值|](预测值减真实值求绝对值后求均值)
mae = mean_absolute_error(predicted_stock_price, real_stock_price)
print('均方误差: %.6f' % mse)
print('均方根误差: %.6f' % rmse)
print('平均绝对误差: %.6f' % mae)

  GRU 股票预测 loss 曲线:
GRU(门控循环单元)实现股票预测_第5张图片
  GRU 股票预测曲线:
GRU(门控循环单元)实现股票预测_第6张图片
  GRU 股票预测评价指标:
GRU(门控循环单元)实现股票预测_第7张图片

  模型摘要:
GRU(门控循环单元)实现股票预测_第8张图片

你可能感兴趣的:(深度学习,gru,lstm,tensorflow,深度学习,神经网络)