DL with python(20)——tensorflow实现RNN股票预测

本文涉及到的是中国大学慕课《人工智能实践:Tensorflow笔记》第六讲第12节的内容,实现循环神经网络(Recurrent Neural Network,RNN)输入60天的价格预测第61天的价格。
RNN这部分的基础知识还是比较复杂的,特别是计算过程,需要深入理解才能掌握数据处理和网络搭建能力。

数据介绍

SH600519.csv 是贵州茅台的日 k 线数据,本次例子中只用它的 C 列数据(如下图所示):用连续 60 天的开盘价,预测第 61 天的开盘价。
**图1**

下载链接:https://pan.baidu.com/s/1doIh1gzNeAR3PUSabYPr1Q
提取码:m1ez

代码实现

第一步,导入相关模块

## 第一步,导入相关模块
import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Dropout, Dense, SimpleRNN
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

第二步,导入数据并划分数据集

首先用pandas读取CSV文件中的数据,将数据赋值到变量maotai,然后从maotai中分割出训练集和测试集(测试集的时间应晚于训练集)。然后利用MinMaxScaler进行归一化处理,建立空列表为进一步划分输入和标签做准备。

## 第二步,导入数据并划分数据集
maotai = pd.read_csv('./SH600519.csv')  # 读取csv文件
# 前(2426-300=2126)天的开盘价作为训练集,表格从0开始计数,2:3 是提取[2:3)列,前闭后开,故提取出第2列即C列开盘价
training_set = maotai.iloc[0:2426 - 300, 2:3].values
# 后300天的开盘价作为测试集
test_set = maotai.iloc[2426 - 300:, 2:3].values
# 归一化
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 天数据作为对应的标签 y_train ,一共生成 2066 组训练数据,然后打乱训练数据的顺序并转变为 array 格式继而转变为 RNN 输入要求的维度 。

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 循环遍历整个测试数据,一共生成 240组测试数据。用于预测的数据不需要打乱,以免造成时间泄露(temporal leak),但需转变为 array 格式继而转变为 RNN 输入要求的维度。

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

第三步,搭建网络结构

用 sequntial 搭建神经网络:第一层循环计算层包含 80 个记忆体,每个时间步推送h𝑡 给下一层,使用 0.2 的 Dropout;第二层循环计算层包含 100 个记忆体,仅最后的时间步推送h𝑡 给下一层,使用 0.2 的 Dropout。由于输出值是第 61 天的开盘价只有一个数,所以全连接 Dense 是 1。

## 第三步,搭建网络结构
model = tf.keras.Sequential([
    SimpleRNN(80, return_sequences=True),
    Dropout(0.2),
    SimpleRNN(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/rnn_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')

第五步,执行训练,

fit执行网络的训练,fit中的相关设置依次为训练集样本,训练集标签,小批量大小64,训练轮次50,测试集,训练集循环1轮次进行一次测试,执行断点续训。

## 第五步,执行训练
history = model.fit(x_train, y_train, batch_size=64, epochs=50, validation_data=(x_test, y_test), validation_freq=1, callbacks=[cp_callback])

第六步,打印网络结构和参数统计

summary显示网络结构和参数统计信息,并将所有参数保存在同文件夹中的txt文本内。

## 第六步,打印网络结构和参数统计
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提取训练过程中网络loss的变化,绘制折线图。

# loss可视化
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()

loss曲线如下所示:
图2

测试结果

利用训练后的网络对测试集进行预测,检测网络的性能,并绘制真实值和预测值对比。

# 测试集输入模型进行预测
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()

绘制的对比图图下所示:
图3

最后通过三种方法来评价预测结果,误差越小,表示预测越准。

## 三个评价指标,误差越小,预测越精确
# 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)

输出结果如下:

均方误差: 503.211814
均方根误差: 22.432383
平均绝对误差: 17.888682
  • 5
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值