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()
相关推荐
EchoL、几秒前
【论文阅读】SteganoGAN:High Capacity Image Steganography with GANs
论文阅读·人工智能·笔记·算法
元智启1 分钟前
企业AI智能体:技术突破与生态融合重构产业新格局——从单点突破到系统重构的产业跃迁
人工智能·重构
CoovallyAIHub2 分钟前
深度学习驱动的视频异常检测(VAD),AI如何让监控更智能?
深度学习·算法·计算机视觉
前端程序猿之路2 分钟前
AI大模型应用之-RAG 全流程
人工智能·python·gpt·语言模型·aigc·mybatis·ai编程
线束线缆组件品替网7 分钟前
Cole Hersee重载环境下汽车线束布线与固定方案全解析
人工智能·汽车·电脑·硬件工程·材料工程
数据皮皮侠AI8 分钟前
数字经济政策工具变量数据(2008-2023)
大数据·数据库·人工智能·笔记·1024程序员节
赫尔·普莱蒂科萨·帕塔11 分钟前
从 “脑梗“ 到 “功夫高手“
数据库·人工智能·agi
雨大王51212 分钟前
AI+工业元宇宙:如何彻底改变传统汽车制造业的运作模式?
人工智能
却道天凉_好个秋15 分钟前
OpenCV(四十五):SURF特征检测
人工智能·opencv·计算机视觉
雷焰财经16 分钟前
iBox探索文化产业数字化路径:标准筑基 生态赋能
大数据·人工智能