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()
相关推荐
Shockang3 小时前
AI 编码智能体生产化工程
人工智能
BerryS3N3 小时前
大模型 (LLM) 全栈技术深度解析与实战指南:从 Transformer 底层原理、三阶段训练范式到 RAG 与 Agent 系统架构
深度学习·系统架构·transformer
jay神4 小时前
深度学习确定baseline之后怎么做改进?
人工智能·深度学习·yolo·计算机视觉·分类
acrel74 小时前
安科瑞Acrel-1000变电站综合自动化系统在合肥某新材料公司35kV综合自动化项目中的应用分析
大数据·人工智能
UWA4 小时前
隐藏视频变“常驻刺客”,VideoPlayer与“N/A”纹理该怎么查
人工智能·性能优化·音视频·memory·cpu·游戏开发
V哥AI增长5 小时前
小红书笔记在生成式AI引擎中的可见性机制解析:从抓取原理到GEO工程化实践
大数据·人工智能·笔记
ajassi20005 小时前
AI语音智能体开发日记(十二)GX8006 固件定制指南——从双唤醒词到 UART 音频传输
人工智能·ai·ai编程
大模型momo5 小时前
告别单体 Agent:多智能体设计模式(Multi-Agent Patterns)深度实战手册
人工智能·agent·multi-agent·多agent
DisonTangor5 小时前
【SeeDream开源平替】MiniMax H3 重磅开源:全模态视频生成新标杆,2K 画质 + 原生立体声,15 秒大片一键生成!
人工智能·ai作画·开源·aigc·音视频
很楠爱上5 小时前
(附上相关学习资源)适合新手做的第一个agent项目*ovo*Dify Agent 全栈实战:从智能选车顾问到新能源汽车之家的端到端开发
人工智能·汽车·agent·项目·开发笔记