基于LSTM循环神经网络的时间序列股价预测

时间序列数据预测是一种利用历史数据来预测未来趋势的技术。这种技术可以被应用于多个领域,如气象预测、交通流量预测、人口统计预测等等。

本文以股票预测为案例基于Python语言实现LSTM循环神经网络的时间序列预测。使用的深度学习框架为Keras。

直接上代码

from pandas import DataFrame
from pandas import Series
from pandas import concat
from pandas import read_csv
from datetime import datetime, date, time
from sklearn.metrics import mean_squared_error
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from math import sqrt
from matplotlib import pyplot
from numpy import array

# 修正数据格式
def parser(x):
	return datetime.strptime('190'+x, '%Y-%m')

# 将时间序列转换成监督学习数据
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
	n_vars = 1 if type(data) is list else data.shape[1]
	df = DataFrame(data)
	cols, names = list(), list()
	# input sequence (t-n, ... t-1)
	for i in range(n_in, 0, -1):
		cols.append(df.shift(i))
		names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]
	# forecast sequence (t, t+1, ... t+n)
	for i in range(0, n_out):
		cols.append(df.shift(-i))
		if i == 0:
			names += [('var%d(t)' % (j+1)) for j in range(n_vars)]
		else:
			names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]
	# put it all together
	agg = concat(cols, axis=1)
	agg.columns = names
	# drop rows with NaN values
	if dropnan:
		agg.dropna(inplace=True)
	return agg

# 数据差分法
def difference(dataset, interval=1):
	diff = list()
	for i in range(interval, len(dataset)):
		value = dataset[i] - dataset[i - interval]
		diff.append(value)
	return Series(diff)

# 数据特征工程,差分,缩放,分割
def prepare_data(series, n_test, n_lag, n_seq):
    # 提取文本中的数据
    raw_values = series.values
    # 对数据进行差分计算
    diff_series = difference(raw_values, 1)
    # 提取差分后的数据
    diff_values = diff_series.values
    print(diff_values)
    # 重构成n行一列的数据
    diff_values = diff_values.reshape(len(diff_values), 1)
    print(diff_values)
    # 定义数据缩放在(-1,1)之间
    scaler = MinMaxScaler(feature_range=(-1, 1))
    print(scaler)
    # 对数据进行缩放
    scaled_values = scaler.fit_transform(diff_values)
    print(scaled_values)
    # 将缩放后的数据重构成n行一列的数据
    scaled_values = scaled_values.reshape(len(scaled_values), 1)
    print(scaled_values)
    # 将数据构建成步长为n_seq的监督学习型数据
    supervised = series_to_supervised(scaled_values, n_lag, n_seq)
    print(supervised)
    supervised_values = supervised.values
    # 将数据分割出n_test条作为测试数据
    train, test = supervised_values[0:-n_test], supervised_values[-n_test:]
    return scaler, train, test

# 你和一个LSTM网络,训练数据
def fit_lstm(train, n_lag, n_seq, n_batch, nb_epoch, n_neurons):
    # 每个4位序列中,第1位作为x,后3位作为预测值y
    X, y = train[:, 0:n_lag], train[:, n_lag:]
    # 重构训练数据结构->[samples, timesteps, features]->[22,1,1]
    X = X.reshape(X.shape[0], 1, X.shape[1])
    print(X)
    print(y)
    # 网络结构
    model = Sequential()
    # 一个神经元, batch_input_shape(1,1,1),传递序列状态
    model.add(LSTM(n_neurons, batch_input_shape=(n_batch, X.shape[1], X.shape[2]), stateful=True))
    model.add(Dense(y.shape[1]))
    model.compile(loss='mean_squared_error', optimizer='adam')
    # 开始训练
    for i in range(nb_epoch):
        # 数据训练1次,每次训练1组数据,不混淆序列顺序
        model.fit(X, y, epochs=1, batch_size=n_batch, verbose=0, shuffle=False)
        # 每次训练完初始化网络状态(不是权重)
        model.reset_states()
    return model

# LSTM 单步预测
def forecast_lstm(model, X, n_batch):
	# 重构输入形状 (1,1,1) [samples, timesteps, features]
	X = X.reshape(1, 1, len(X))
	# 预测张量形状为 (1,3)
	forecast = model.predict(X, batch_size=n_batch)
	# 将预测结果[[XX,XX,XX]]转换成list数组
	return [x for x in forecast[0, :]]

# 用模型进行预测
def make_forecasts(model, n_batch, test, n_lag, n_seq):
    forecasts = list()
    # 对X值进行逐个预测
    for i in range(len(test)):
        # X, y = test[i, 0:n_lag], test[i, n_lag:]
        X = test[i, 0:n_lag]
        # LSTM 单步预测
        forecast = forecast_lstm(model, X, n_batch)
        # 存储预测数据
        forecasts.append(forecast)
    return forecasts

# 对预测数据逆差分
def inverse_difference(last_ob, forecast):
	# invert first forecast
	inverted = list()
	inverted.append(forecast[0] + last_ob)
	# propagate difference forecast using inverted first value
	for i in range(1, len(forecast)):
		inverted.append(forecast[i] + inverted[i-1])
	return inverted

# 对预测后的数据逆转换
def inverse_transform(series, forecasts, scaler, n_test):
	inverted = list()
	for i in range(len(forecasts)):
		# create array from forecast
		forecast = array(forecasts[i])
		forecast = forecast.reshape(1, len(forecast))
		# 数据逆缩放
		inv_scale = scaler.inverse_transform(forecast)
		inv_scale = inv_scale[0, :]
		# 数据逆差分
		index = len(series) - n_test + i - 1
		last_ob = series.values[index]
		inv_diff = inverse_difference(last_ob, inv_scale)
		# 存储转换后的数据
		inverted.append(inv_diff)
	return inverted

# 评估预测结果的均方差
def evaluate_forecasts(test, forecasts, n_lag, n_seq):
	for i in range(n_seq):
		actual = [row[i] for row in test]
		predicted = [forecast[i] for forecast in forecasts]
		rmse = sqrt(mean_squared_error(actual, predicted))
		print('t+%d RMSE: %f' % ((i+1), rmse))

# 作图
def plot_forecasts(series, forecasts, n_test):
	# plot the entire dataset in blue
	pyplot.plot(series.values)
	# plot the forecasts in red
	for i in range(len(forecasts)):
		if i==0:
			off_s = len(series) - n_test + i - 1
			off_e = off_s + len(forecasts[i]) + 1
			xaxis = [x for x in range(off_s, off_e)]
			yaxis = [series.values[off_s]] + forecasts[i]
			pyplot.plot(xaxis, yaxis, color='red')
	# show the plot
	pyplot.show()

# 加载数据
series = read_csv('shampoo-sales.csv', header=0, parse_dates=[0], index_col=0,  date_parser=parser)
# 参数配置
n_seq = 10       # 预测三个数据
n_test = 3     # 测试数据为10组
n_epochs = 1500 # 训练1500次
n_neurons =1   # 神经节点为1
n_lag = 1      # 步长
n_batch = 1     # 每次训练几组数据
# 数据差分,缩放,重构成监督学习型数据
scaler, train, test = prepare_data(series, n_test, n_lag, n_seq)
# 拟合模型
model = fit_lstm(train, n_lag, n_seq, n_batch, n_epochs, n_neurons)
# 开始预测
forecasts = make_forecasts(model, n_batch, test, n_lag, n_seq)
# 将预测后的数据逆转换
forecasts = inverse_transform(series, forecasts, scaler, n_test+2)
# 从测试数据中分离出y对应的真实值
actual = [row[n_lag:] for row in test]
# 对真实值逆转换
actual = inverse_transform(series, actual, scaler, n_test+2)
# 评估预测值和真实值的RSM
evaluate_forecasts(actual, forecasts, n_lag, n_seq)
# 作图
plot_forecasts(series, forecasts, n_test+2)

当循环100次,采用100个神经网络元节点时预测效果图如下:

基于LSTM循环神经网络的时间序列股价预测_第1张图片

当循环1500次,采用1个神经网络元节点时预测效果图如下:

基于LSTM循环神经网络的时间序列股价预测_第2张图片

 可以看出,红色的预测数据以及非常逼近预期数据。

项目源码请看评论。

原理

实现

技术分支

关键词

keras

基于TensorFlow在高层开发的深度学习框架

matplotlib

数据图形化

pandas

数据分析 数据处理

监督学习

监督学习是指:利用一组已知类别的样本调整分类器的参数,使其达到所要求性能的过程,也称为监督训练或有教师学习。

编码器解码器

编码器和解码器广泛应用于图像处理、自然语言处理等领域,如图像压缩、语音识别、图像生成等任务。其中编码器主要用于特征提取和数据压缩,而解码器主要用于数据重建和生成。而在生成对抗网络中,生成器则主要用于生成高质量的图像、音频等数据,判别器则主要用于区分真实数据和生成数据。编码器和解码器广泛应用于图像处理、自然语言处理等领域,如图像压缩、语音识别、图像生成等任务。其中编码器主要用于特征提取和数据压缩,而解码器主要用于数据重建和生成。而在生成对抗网络中,生成器则主要用于生成高质量的图像、音频等数据,判别器则主要用于区分真实数据和生成数据。

有状态网络

stateful LSTM:

       能让模型学习到你输入的samples之间的时序特征,适合一些长序列的预测,哪个sample在前,哪个sample在后对模型是有影响的。

       优点:更小的网络,或更少的训练时间。

       缺点:需要使用反应数据周期性的批大小来训练网络,并在每个训练批后重置状态。

stateless LSTM:

        输入samples后,默认就会shuffle,可以说是每个sample独立,之间无前后关系,适合输入一些没有关系的样本。

例子

stateful LSTM:我想根据一篇1000句的文章预测第1001句,每一句是一个sample。我会选用stateful,因为这文章里的1000句是有前后关联的,是有时序的特征的,我不想丢弃这个特征。利用这个时序性能让第一句的特征传递到我们预测的第1001句。(batch_size = 10时)

stateless LSTM:我想训练LSTM自动写诗句,我想训练1000首诗,每一首是一个sample,我会选用stateless LSTM,因为这1000首诗是独立的,不存在关联,哪怕打乱它们的顺序,对于模型训练来说也没区别。

原文链接:https://blog.csdn.net/qq_27586341/article/details/88239404

过度拟合

将个别噪声的样本特征作为依据导致判断出错

损失函数

一言以蔽之,损失函数(loss function)就是用来度量模型的预测值f(x)与真实值Y的差异程度的运算函数,它是一个非负实值函数,通常使用L(Y, f(x))来表示,损失函数越小,模型的鲁棒性就越好。

为什么使用损失函数?

损失函数使用主要是在模型的训练阶段,每个批次的训练数据送入模型后,通过前向传播输出预测值,然后损失函数会计算出预测值和真实值之间的差异值,也就是损失值。得到损失值之后,模型通过反向传播去更新各个参数,来降低真实值与预测值之间的损失,使得模型生成的预测值往真实值方向靠拢,从而达到学习的目的

有哪些损失函数?

3.1 基于距离度量的损失函数

基于距离度量的损失函数通常将输入数据映射到基于距离度量的特征空间上,如欧氏空间、汉明空间等,将映射后的样本看作空间上的点,采用合适的损失函数度量特征空间上样本真实值和模型预测值之间的距离。特征空间上两个点的距离越小,模型的预测性能越好。

3.1.1 均方误差损失函数(MSE)

在回归问题中,均方误差损失函数用于度量样本点到回归曲线的距离,通过最小化平方损失使样本点可以更好地拟合回归曲线。均方误差损失函数(MSE)的值越小,表示预测模型描述的样本数据具有越好的精确度。由于无参数、计算成本低和具有明确物理意义等优点,MSE已成为一种优秀的距离度量方法。尽管MSE在图像和语音处理方面表现较弱,但它仍是评价信号质量的标准,在回归问题中,MSE常被作为模型的经验损失或算法的性能指标。

3.1.2 L2损失函数

L2损失又被称为欧氏距离,是一种常用的距离度量方法,通常用于度量数据点之间的相似度。由于L2损失具有凸性和可微性,且在独立、同分布的高斯噪声情况下,它能提供最大似然估计,使得它成为回归问题、模式识别、图像处理中最常使用的损失函数。

3.1.3 L1损失函数

L1损失又称为曼哈顿距离,表示残差的绝对值之和。

3.1.4 Smooth L1损失函数

Smooth L1损失是由Girshick R在Fast R-CNN中提出的,主要用在目标检测中防止梯度爆炸。

3.1.5 huber损失函数

3.2 基于概率分布度量的损失函数

3.2.1 KL散度函数(相对熵)

3.2.2 交叉熵损失

3.2.3 softmax损失函数

3.2.4 Focal loss

如何选择损失函数?

通常情况下,损失函数的选取应从以下方面考虑:

(1) 选择最能表达数据的主要特征来构建基于距离或基于概率分布度量的特征空间。

(2)选择合理的特征归一化方法,使特征向量转换后仍能保持原来数据的核心内容。

(3)选取合理的损失函数,在实验的基础上,依据损失不断调整模型的参数,使其尽可能实现类别区分。

(4)合理组合不同的损失函数,发挥每个损失函数的优点,使它们能更好地度量样本间的相似性。

(5)将数据的主要特征嵌入损失函数,提升基于特定任务的模型预测精确度

归一化

简而言之,归一化的目的就是使得预处理的数据被限定在一定的范围内(比如[0,1]或者[-1,1]),从而消除奇异样本数据导致的不良影响。

几种归一化的方法

1 最大最小标准化(Min-Max Normalization)

2 z—score 标准化

3 神经网络归一化

(1)log对数函数归一化

(2)反正切函数归一化

4 L2范数归一化

定义:特征向量中每个元素均除以向量的L2范数

什么时候用归一化?

(1)如果对输出结果范围有要求,用归一化。

(2)如果数据较为稳定,不存在极端的最大最小值,用归一化。

(3)如果数据存在异常值和较多噪音,用标准化,可以间接通过中心化避免异常值和极端值的影响

张量

张量可以看作是一个多维数组(矩阵)。标量可以看作是0维张量,向量可以看作1维张量,矩阵可以看作是二维张量。如果你之前用过NumPy,你会发现Tensor和NumPy的多维数组非常类似。

信息熵

这里我再说一个对信息熵的理解。信息熵还可以作为一个系统复杂程度的度量,如果系统越复杂,出现不同情况的种类越多,那么他的信息熵是比较大的。

如果一个系统越简单,出现情况种类很少(极端情况为1种情况,那么对应概率为1,那么对应的信息熵为0),此时的信息熵较小。

RMSE

均方根误差,亦称标准误差,其定义为i=1,2,3,…n。在有限测量次数中,均方根误差常用下式表示:√[∑di^2/n]=Re,式中:n为测量次数;di为一组测量值与真值的偏差。如果误差统计分布是正态分布,那么随机误差落在±σ以内的概率为68%。

单步预测

只预测N+1的值。不同于多步预测

多步预测

你可能感兴趣的:(深度学习,python,深度学习,rnn,lstm)