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()
相关推荐
小阿鑫6 分钟前
不要太信任Cursor,这位网友被删库了。。。
人工智能·aigc·cursor·部署mcp
说私域42 分钟前
基于定制开发开源 AI 智能名片 S2B2C 商城小程序的热点与人工下发策略研究
人工智能·小程序
Tiger Z1 小时前
《动手学深度学习v2》学习笔记 | 1. 引言
pytorch·深度学习·ai编程
GoGeekBaird2 小时前
GoHumanLoopHub开源上线,开启Agent人际协作新方式
人工智能·后端·github
Jinkxs2 小时前
测试工程师的AI转型指南:从工具使用到测试策略重构
人工智能·重构
别惹CC2 小时前
Spring AI 进阶之路01:三步将 AI 整合进 Spring Boot
人工智能·spring boot·spring
stbomei4 小时前
当 AI 开始 “理解” 情感:情感计算技术正在改写人机交互规则
人工智能·人机交互
Moshow郑锴9 小时前
人工智能中的(特征选择)数据过滤方法和包裹方法
人工智能
TY-20259 小时前
【CV 目标检测】Fast RCNN模型①——与R-CNN区别
人工智能·目标检测·目标跟踪·cnn
CareyWYR10 小时前
苹果芯片Mac使用Docker部署MinerU api服务
人工智能