LSTM时间序列数据训练+预测的基本实现

文章目录

🧡🧡前言🧡🧡

最近数模比赛中经常遇到时间序列预测的问题,奈何在比赛中没有时间细细了解,导致总是匆匆忙忙一个ARIMA时间序列分析就糊弄过去了。趁有空学习和总结一下实现思路。

🧡🧡实现🧡🧡

简单起见,先考虑用一个特征预测Y的情况(即只用标签本身预测)。

数据集

数据集 :Google Stock Prize of 10 years 谷歌股票数据集

下载:https://www.kaggle.com/datasets/parthsojitra/google-stock-prize-of-10-years/data

本次只使用google_stock_train.csv来训练+测试,另一个文件不考虑。

代码流程

导入相关库

python 复制代码
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 keras import optimizers
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error
import time

如下,google_stock_train.csv总共含有2265天,为方便实现过程中的维度计算,这里取前1000天。

python 复制代码
# ================import data file================
df = pd.read_csv('./sample_data/google_stock_train.csv',
                        header=0, parse_dates=[0],
                        index_col=0, usecols=[0, 1])

df_1000=df[:1000]
df_values=df_1000.values # 转成array

归一化处理

python 复制代码
# ================归一化================
scaler = MinMaxScaler(feature_range=(0,1))
scaler.fit(df_values)
df_values=scaler.transform(df_values)

拆分train和test集,并且创建序列数据,如下例子,当look_back=3时,即将每一天的前3天用来预测该天。

python 复制代码
# ================8:2拆分出train和test================
test_spilt_number=round(len(df_values)*0.20) # 8:2 spilt
train=df_values[:-test_spilt_number] # 负号表示倒数
test=df_values[-test_spilt_number:]

# ================将train、test数据凑出序列数据================
look_back=20 # 设置用前多少天预测
def createXY(dataset,look_back): # dataset为array类型, look_back即为利用前多少个数据预测
    dataX = []
    dataY = []
    for i in range(len(dataset)-look_back):
            dataX.append(dataset[i:i+look_back, 0:dataset.shape[1]]) # 从0到20行(不包含20)
            dataY.append(dataset[i,0]) # 第[20]行
    return np.array(dataX),np.array(dataY)

trainX,trainY=createXY(train,look_back) # create 序列数据
testX,testY=createXY(test,look_back)

print("trainX Shape-- ",trainX.shape) # 【samples, step, features】
print("trainY Shape-- ",trainY.shape) # 【samples】
print("testX Shape-- ",testX.shape)
print("testY Shape-- ",testY.shape)

输出结果:可以看到,设置look_back=20时,对于train集(800个样本),可以拆分出780个新样本,每个新样本中由原来的每段20天样本组成,而最后的维度1代表特征数(这里先考虑只包含1列特征,即标签本身)

构建模型(参考别人的,具体细节不是很懂,日后再补一补吧)

python 复制代码
# ================create model================
model = Sequential() # 创建一个序贯模型,可以简单地一层接一层地添加神经网络层
model.add(LSTM(input_dim=1, units=50, return_sequences=True)) # input_dim为样本特征数,units为LSTM单元神经元数,简单理解为输出维度,
                                # return_sequences=True 表示返回完整序列
#model.add(Dropout(0.2)) # 用于在训练过程中随机丢弃部分节点,以防止过拟合。
model.add(LSTM(input_dim=50, units=100, return_sequences=True))
#model.add(Dropout(0.2))
model.add(LSTM(input_dim=100, units=200, return_sequences=True))
#model.add(Dropout(0.2))
model.add(LSTM(300, return_sequences=False)) # return_sequences=True 表示返回一个值,即输出
model.add(Dropout(0.2))
model.add(Dense(100))
model.add(Dense(units=1)) # 添加了一个全连接层,输出维度为1,用于预测目标值
model.add(Activation('relu')) # 激活函数
start = time.time()
model.compile(loss='mean_squared_error', optimizer='Adam') # 损失函数和优化器 
history = model.fit(trainX, trainY, batch_size=64, epochs=50,
                    validation_split=0.1, verbose=2) # 训练
# loss iter
fig1 = plt.figure(figsize=(12, 8))
plt.plot(history.history['loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.show()

loss迭代图

用testX预测,并将预测结果与testY做对比

python 复制代码
# ================test error================
test_pred_Y = model.predict(testX) # 用testX预测出Y
test_pred_Y = scaler.inverse_transform(test_pred_Y) # 逆归一化
testY_inv = scaler.inverse_transform(testY.reshape(-1,1)) # 将shape:(x,)调整为shape:(x,1)

# test fit with original Dataset
fig2 = plt.figure(figsize=(12, 8))
plt.plot(test_pred_Y, color="green", label='test')
plt.plot(testY_inv, color='blue', label='dataset')
plt.ylabel('price')
plt.xlabel('date')
plt.legend()
plt.show()

趋势比较像,具体数值还有待提高

预测未来50天,思路是先取原数据的最后look_back天(20天),即981-1000天,然后组合这20天样本丢入model中预测第1001天,然后再用982-1001天这20天继续丢入model中预测第1002天,以此类推。

python 复制代码
# ================pred================
pred_future_num=50
# 扩张array,先填入0占位
look_back_data=df_values[-look_back:] # 维度为(look_back,)
for i in range(pred_future_num):
  look_back_data=np.append(look_back_data, 0)
look_back_data=look_back_data.reshape(-1,1) # 维度为(look_back+pred_future_num,1)
# print(look_back_data.shape) 

# pred
for i in range(len(look_back_data)-look_back):
  input_X=look_back_data[i:i+look_back] # 维度为(look_back+pred_future_num,1)
  input_X = np.expand_dims(input_X, axis=0)  # 维度为(1,look_back+pred_future_num,1)
  out_Y=model.predict(input_X)
  look_back_data[i+look_back]=out_Y

look_back_data=scaler.inverse_transform(look_back_data) # 再逆变换
print(look_back_data)

# draw
fig3 = plt.figure(figsize=(12, 8))
days=np.arange(1000-look_back+1, 1000+pred_future_num+1).reshape(-1, 1)
plt.plot(days, look_back_data, label="pred",color='green',linewidth=3)
plt.plot(days, list(df.iloc[1000-look_back:1000+pred_future_num,0]),label="oridata",color='blue',)
plt.legend()
plt.show()

嗯不太成功的模型呜呜呜,可能是原数据取的范围不太有规律,也可能是模型调参啥的问题,后续再看看吧。

大概流程就是这样.

🧡🧡完整代码🧡🧡

python 复制代码
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 keras import optimizers
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error
import time
# ================import data file================
df = pd.read_csv('./sample_data/google_stock_train.csv',
                        header=0, parse_dates=[0],
                        index_col=0, usecols=[0, 1])

df_1000=df[:1000]
df_values=df_1000.values # 转成array

# ================归一化================
scaler = MinMaxScaler(feature_range=(0,1))
scaler.fit(df_values)
df_values=scaler.transform(df_values)

# ================8:2拆分出train和test================
test_spilt_number=round(len(df_values)*0.20) # 8:2 spilt
train=df_values[:-test_spilt_number] # 负号表示倒数
test=df_values[-test_spilt_number:]

# ================将train、test数据凑出序列数据================
look_back=20 # 设置用前多少天预测
def createXY(dataset,look_back): # dataset为array类型, look_back即为利用前多少个数据预测
    dataX = []
    dataY = []
    for i in range(len(dataset)-look_back):
            dataX.append(dataset[i:i+look_back, 0:dataset.shape[1]]) # 从0到20行(不包含20)
            dataY.append(dataset[i,0]) # 第[20]行
    return np.array(dataX),np.array(dataY)

trainX,trainY=createXY(train,look_back) # create 序列数据
testX,testY=createXY(test,look_back)

print("trainX Shape-- ",trainX.shape) # 【samples, step, features】
print("trainY Shape-- ",trainY.shape) # 【samples】
print("testX Shape-- ",testX.shape)
print("testY Shape-- ",testY.shape)

# ================create model================
model = Sequential() # 创建一个序贯模型,可以简单地一层接一层地添加神经网络层
model.add(LSTM(input_dim=1, units=50, return_sequences=True)) # input_dim为样本特征数,units为LSTM单元神经元数,简单理解为输出维度,
                                # return_sequences=True 表示返回完整序列
#model.add(Dropout(0.2)) # 用于在训练过程中随机丢弃部分节点,以防止过拟合。
model.add(LSTM(input_dim=50, units=100, return_sequences=True))
#model.add(Dropout(0.2))
model.add(LSTM(input_dim=100, units=200, return_sequences=True))
#model.add(Dropout(0.2))
model.add(LSTM(300, return_sequences=False)) # return_sequences=True 表示返回一个值,即输出
model.add(Dropout(0.2))
model.add(Dense(100))
model.add(Dense(units=1)) # 添加了一个全连接层,输出维度为1,用于预测目标值
model.add(Activation('relu')) # 激活函数
start = time.time()
model.compile(loss='mean_squared_error', optimizer='Adam') # 损失函数和优化器 
history = model.fit(trainX, trainY, batch_size=64, epochs=50,
                    validation_split=0.1, verbose=2) # 训练 
# loss iter
fig1 = plt.figure(figsize=(12, 8))
plt.plot(history.history['loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.show()

# ================test error================
test_pred_Y = model.predict(testX) # 用testX预测出Y
test_pred_Y = scaler.inverse_transform(test_pred_Y) # 逆归一化
testY_inv = scaler.inverse_transform(testY.reshape(-1,1)) # 将shape:(x,)调整为shape:(x,1)

# test fit with original Dataset
fig2 = plt.figure(figsize=(12, 8))
plt.plot(test_pred_Y, color="green", label='test')
plt.plot(testY_inv, color='blue', label='dataset')
plt.ylabel('price')
plt.xlabel('date')
plt.legend()
plt.show()

# ================pred================
pred_future_num=50
# 扩张array,先填入0占位
look_back_data=df_values[-look_back:] # 维度为(look_back,)
for i in range(pred_future_num):
  look_back_data=np.append(look_back_data, 0)
look_back_data=look_back_data.reshape(-1,1) # 维度为(look_back+pred_future_num,1)
# print(look_back_data.shape) 

# pred
for i in range(len(look_back_data)-look_back):
  input_X=look_back_data[i:i+look_back] # 维度为(look_back+pred_future_num,1)
  input_X = np.expand_dims(input_X, axis=0)  # 维度为(1,look_back+pred_future_num,1)
  out_Y=model.predict(input_X)
  look_back_data[i+look_back]=out_Y

look_back_data=scaler.inverse_transform(look_back_data) # 再逆变换
print(look_back_data)

# draw
fig3 = plt.figure(figsize=(12, 8))
days=np.arange(1000-look_back+1, 1000+pred_future_num+1).reshape(-1, 1)
plt.plot(days, look_back_data, label="pred",color='green',linewidth=3)
plt.plot(days, list(df.iloc[1000-look_back:1000+pred_future_num,0]),label="oridata",color='blue',)
plt.legend()
plt.show()
相关推荐
袁牛逼3 分钟前
ai外呼机器人的作用有哪些?
人工智能·机器人
BSV区块链14 分钟前
如何在BSV区块链上实现可验证AI
人工智能·区块链
武子康30 分钟前
大数据-212 数据挖掘 机器学习理论 - 无监督学习算法 KMeans 基本原理 簇内误差平方和
大数据·人工智能·学习·算法·机器学习·数据挖掘
deephub31 分钟前
Tokenformer:基于参数标记化的高效可扩展Transformer架构
人工智能·python·深度学习·架构·transformer
Q81375746037 分钟前
数据挖掘在金融交易中的应用:民锋科技的智能化布局
人工智能·科技·数据挖掘
qzhqbb41 分钟前
语言模型的采样方法
人工智能·语言模型·自然语言处理
qzhqbb43 分钟前
基于 Transformer 的语言模型
人工智能·语言模型·自然语言处理·transformer
___Dream44 分钟前
【CTFN】基于耦合翻译融合网络的多模态情感分析的层次学习
人工智能·深度学习·机器学习·transformer·人机交互
极客代码1 小时前
【Python TensorFlow】入门到精通
开发语言·人工智能·python·深度学习·tensorflow
义小深1 小时前
TensorFlow|咖啡豆识别
人工智能·python·tensorflow