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()
相关推荐
__Benco2 分钟前
OpenHarmony平台驱动使用(十五),SPI
人工智能·驱动开发·harmonyos
Listennnn3 分钟前
AI系统的构建
人工智能·系统架构
新智元6 分钟前
全球 30 名顶尖数学家秘密集会围剿 AI,当场破防!惊呼已接近数学天才
人工智能·openai
楽码11 分钟前
AI决策树:整理繁杂问题的简单方法
人工智能·后端·openai
星辰大海的精灵15 分钟前
基于Dify+MCP实现通过微信发送天气信息给好友
人工智能·后端·python
ReturnOfMars17 分钟前
AI本地批量生图Agent-Jaaz体验,确实强
人工智能
柠檬味拥抱18 分钟前
人工智能在教育中的角色-AI Agent助力个性化学习与学生辅导
人工智能
只有左边一个小酒窝19 分钟前
(六)卷积神经网络:深度学习在计算机视觉中的应用
深度学习·计算机视觉·cnn
精灵vector20 分钟前
Agent短期记忆的几种持久化存储方式
人工智能·python
大模型之路25 分钟前
基于本地LLM与MCP架构构建AI智能体全指南
人工智能·架构