前言
时序问题是数据挖掘过程中常见的一个业务场景,机器学习模型中也有像ARIMA,SARIMA等等优秀的模型,同样很多神经网络模型也可以有效解决时序问题,本次就用RNN神经网络对分析股票成交量的走势。
股票数据集下载:https://pan.baidu.com/s/1S5Dsq2oH_1T7IKSoDdh6Jg
提取码:DJNB
数据可视化
首先导入本次需要用到的所有可能用到的库
from tensorflow.keras import layers
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime
from sklearn.preprocessing import MinMaxScaler
import statsmodels.api as sm
import matplotlib.dates as dates
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import math
from keras.models import Sequential
from keras.layers import Dense, Activation, Dropout, LSTM
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error
from keras import optimizers
import time
读入数据集,对数据集进行归一化处理,然后将数据集划分为训练集和测试集:
#数据读取和预处理
train=pd.read_csv('股票数据.csv',usecols=[0, 5],parse_dates=[0],index_col=0)
#对数据集进行可视化
plt.figure(figsize=(20, 10))
plt.plot(train['volume'],color='r')
plt.ylabel('volume')
plt.xlabel('date')
plt.show()
train = train.values
scaler = MinMaxScaler(feature_range=(0, 1))
train = scaler.fit_transform(train.reshape(-1, 1))
#划分训练集和测试集
train_size = int(len(train)*0.8)
test_size = len(train)-train_size
test=train[train_size: len(train)]
train=train[0: train_size]
数据集整体分布如下图:
数据集构建
然后是进行输入数据集的构建,RNN模型的输入是矩阵格式,而且数据是三个维度的,因为RNN和LSTM都是循环神经网络,循环神经网络的输出数据会作为输入数据再次输入网络中,所有对应在时间维度具有高依赖性的数据我们采用RNN的效果非常好,神经网络可以提取出数据在时间维度上的特征。这里的time_back就是需要前面几个数据来对后面的数据进行预测,可以自行改变time_back的值,也会有差异。
#数据集构建
def dataset_to_array(dataset, time_back):
dataX=[]
dataY=[]
for i in range(len(dataset)-time_back-1):
a = dataset[i: (i+time_back)]
dataX.append(a)
dataY.append(dataset[i+time_back])
return np.array(dataX), np.array(dataY)
time_back = 1
trainX, trainY = dataset_to_array(train, time_back)
testX, testY = dataset_to_array(test, time_back)
模型构建及训练
这里我就简单地构建了一个RNN模型,因为数据集比较小,而且数据简单。模型构建方面可以自行改变了有很多,可以加隐藏层,可以控制神经元个数,也可以为防止过拟合做一些调整,优化器和激活函数都可以自行改变,效果可能都会有差异。
#RNN模型构建
np.random.seed(2017)
model=tf.keras.models.Sequential([
tf.keras.layers.SimpleRNN(input_dim=1, units=50, return_sequences=True),
tf.keras.layers.SimpleRNN(units=128),
tf.keras.layers.Dense(units=64,activation='sigmoid'),
tf.keras.layers.Dense(units=1,activation='sigmoid')
])
model.compile(optimizer=keras.optimizers.Adam(0.01),loss=keras.losses.mean_squared_error)
model_information=model.fit(trainX,trainY,epochs=100,verbose=1)
information_loss=model_information.history['loss'] #模型训练损失
#模型损失可视化
def loss(information_loss):
plt.figure(figsize=(12, 8))
plt.plot(information_loss)
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.show()
loss(information_loss)
模型训练好后就对模型的损失进行一个可视化,可以看到模型还是收敛的,损失最终趋于稳定:
模型预测
模型训练好后就对测试集进行预测,然后将模型对测试集的预测结果和测试集的真实值进行一个可视化对比。
#对测试集进行预测
testPredict = model.predict(testX)
testPredict = scaler.inverse_transform(testPredict)
testY = scaler.inverse_transform(testY)
testScore = math.sqrt(mean_squared_error(testY, testPredict[:, 0]))
print('测试集的RMSE分数 %.2f' %(testScore))
#测试集进行可视化
plt.figure(figsize=(15, 5))
#plt.plot(range(len(testPredict)-1), testPredict[1:], label='prediction', lineWidth=1)
plt.plot(range(len(testPredict)), testPredict, label='prediction', lineWidth=1)
plt.plot(range(len(testY)), testY, label='true', lineWidth=1)
plt.ylabel('volume')
plt.xlabel('date')
plt.legend()
plt.title("prediction and true")
plt.show()
在模型进行可视化的时候出现了一个非常有趣的问题,可以看到下图有一个明显的滞后问题,测试集的预测结果总是比真实值慢了一步,这里的问题在于我们在构建数据集的时候是选择前一次的数据作为后一次数据的预测,所以模型在预测的时候就是将前一次的值加上损失之后就作为预测值了(这是我的愚见,如果有错误请指正)。所以其实这个模型是没啥实际用的,也没学到太多的东西,一方面数据量也不大,一方面时间也比较短,不太具有说服力。
如果想看着更加准确一点,就需要将测试集时间提前一天,用上面我注释的代码即可效果如下图:
源码也可以通过以下地址获取:https://github.com/CquptDJ/CquptDJ/tree/main
写在最后
关于RNN滞后问题,如果有更懂的大佬能做出更好的解释欢迎评论,我也会查阅更多资料。本人才疏学浅,如果有错误或者理解不到位的地方请指正!