基于LSTM模型的多输入多输出单步时间序列预测

数据集为某天气预报数据,该数据集时间维度为2013年1月1日至2017年4月24日,存在 3 个特征分别是 meantemp, humidity, meanpressure, 接下来将以这三个特征为输入、输出,建立一个多输入多输出的LSTM模型

1. 实现流程

代码实现基于LSTM多输入多输出模型的时间序列预测与分析,下面是代码的实现流程:

  • 数据准备:

使用 pandas 库读取训练集和测试集的数据

对数据进行归一化处理,使用 MinMaxScaler 进行归一化,确保数据在相同的范围内

  • 数据预处理:

定义函数 prepare_data() 将数据转换为适合 LSTM 模型的格式也就是时间窗口划分,构建输入特征序列和对应的目标值序列

  • 构建模型:

使用 Keras 库构建多输入多输出的 LSTM 模型

定义输入层、LSTM 层、全连接层和输出层,其中输出层有三个分支分别预测 meantemp、humidity 和 meanpressure

编译模型,指定损失函数为均方误差(MSE)和优化器为 Adam

  • 模型训练:

使用 fit() 方法对模型进行训练,传入训练集和测试集,设置 epochs 和 batch_size

  • 模型评估:

使用模型对测试集进行预测,计算均方误差(MSE)、均方根误差(RMSE)、平均绝对误差(MAE)和拟合优度(R^2)等指标

  • 未来预测:

定义函数 predict_next_11_days() 预测未来 11 天的数据,利用模型的预测结果进行迭代预测

  • 可视化:

使用 Matplotlib 库绘制训练集、测试集、模型预测结果和未来预测结果的时序图

整个流程涵盖了数据处理、模型构建、训练、评估和预测,以及结果的可视化和分析

2. 代码实现

2.1 数据展示


          
import pandas as pd
          
import matplotlib.pyplot as plt
          
plt.rcParams['font.sans-serif'] = 'SimHei' # 设置中文显示
          
plt.rcParams['axes.unicode_minus'] = False
          

          
df_train = pd.read_excel('训练集.xlsx', index_col=0, parse_dates=['date'])
          
df_test = pd.read_csv('测试集.csv', index_col=0, parse_dates=['date'])
          
df_train
      

picture.image

其中df_train和df_test分别为模型的训练集和测试集,数据不存在缺失值、异常值

2.2 时序图

2.2.1 训练集时序图


          
plt.figure(figsize=(15, 10))
          
plt.subplot(3, 1, 1)
          
plt.plot(df_train['meantemp'], color='y',  alpha=0.3)
          
plt.title('meantemp时序图')
          
plt.grid(True)
          
plt.subplot(3, 1, 2)
          
plt.plot(df_train['humidity'], color='y',  alpha=0.3)
          
plt.title('humidity时序图')
          
plt.grid(True)
          
plt.subplot(3, 1, 3)
          
plt.plot(df_train['meanpressure'], color='y',  alpha=0.3)
          
plt.title('meanpressure时序图')
          
plt.grid(True)
          
plt.show()
      

picture.image

2.2.2 测试集时序图


          
plt.figure(figsize=(15, 10))
          
plt.subplot(3, 1, 1)
          
plt.plot(df_test['meantemp'], color='g',  alpha=0.3)
          
plt.title('meantemp时序图')
          
plt.grid(True)
          
plt.subplot(3, 1, 2)
          
plt.plot(df_test['humidity'], color='g',  alpha=0.3)
          
plt.title('humidity时序图')
          
plt.grid(True)
          
plt.subplot(3, 1, 3)
          
plt.plot(df_test['meanpressure'], color='g',  alpha=0.3)
          
plt.title('meanpressure时序图')
          
plt.grid(True)
          
plt.show()
      

picture.image

2.3 数据0-1标准化


          
from sklearn.preprocessing import MinMaxScaler
          

          
def normalize_dataframe(train_df, test_df):
          
    scaler = MinMaxScaler()
          
    scaler.fit(train_df)  # 在训练集上拟合归一化模型
          
    train_data = pd.DataFrame(scaler.transform(train_df), columns=train_df.columns, index = df_train.index)
          
    test_data = pd.DataFrame(scaler.transform(test_df), columns=test_df.columns, index = df_test.index)
          
    return train_data, test_data
          

          
data_train, data_test = normalize_dataframe(df_train, df_test)
          
data_train
      

picture.image

归一化时只使用训练集的统计量,并将归一化后的转换应用于训练集和测试集,避免直接对所有数据集进行归一化处理从而产生信息泄露

2.4 滑动窗口划分数据


          
def prepare_data(data, win_size, target_feature_idxs):
          
    num_features = data.shape[1]
          
    X = []  
          
    y = []  
          
    for i in range(len(data) - win_size):
          
        temp_x = data[i:i + win_size, :]  
          
        temp_y = [data[i + win_size, idx] for idx in target_feature_idxs]  
          
        X.append(temp_x)
          
        y.append(temp_y)
          
    X = np.asarray(X)
          
    y = np.asarray(y)
          

          
    return X, y
          

          
win_size = 12 # 时间窗口
          
target_feature_idxs = [0, 1, 2] # 指定待预测特征列索引
          
train_x, train_y = prepare_data(data_train.values, win_size, target_feature_idxs)
          
test_x, test_y = prepare_data(data_test.values, win_size, target_feature_idxs)
          
print("训练集形状:", train_x.shape, train_y.shape)
          
print("测试集形状:", test_x.shape, test_y.shape)
      

picture.image

训练集形状 (1449, 12, 3) 表示:

1449:样本数,即训练集中有1449个样本。

12:时间窗口大小,每个样本有12个时间步长的数据,用于预测下一个时间步的数据。

3:特征数,每个时间步长有3个特征(meantemp、humidity 和 meanpressure)

测试集形状 (102, 12, 3) 表示:

102:样本数,即测试集中有102个样本

12:时间窗口大小,每个样本有12个时间步长的数据,用于预测下一个时间步的数据

3:特征数,每个时间步长有3个特征(meantemp、humidity 和 meanpressure)

2.5 模型建立


          
from keras.layers import LSTM, Dense
          
from keras.models import Model
          
from keras.layers import Input
          

          
# 输入维度
          
input_shape = Input(shape=(train_x.shape[1], train_x.shape[2]))
          

          
# LSTM层
          
lstm_layer = LSTM(128, activation='relu')(input_shape)
          

          
# 全连接层
          
dense_1 = Dense(64, activation='relu')(lstm_layer)
          
dense_2 = Dense(32, activation='relu')(dense_1)
          

          
# 输出层
          
output_1 = Dense(1, name='meantemp')(dense_2)
          
output_2 = Dense(1, name='humidity')(dense_2)
          
output_3 = Dense(1, name='meanpressure')(dense_2)
          

          

          
model = Model(inputs = input_shape, outputs = [output_1, output_2, output_3])
          
model.compile(loss='mse', optimizer='adam')
          
# 模型拟合
          
history = model.fit(train_x, [train_y[:,i] for i in range(train_y.shape[1])], epochs=100, batch_size=32, validation_data=(test_x, [test_y[:,i] for i in range(test_y.shape[1])]))
          

          
plt.figure()
          
plt.plot(history.history['loss'], c='b', label='loss')
          
plt.plot(history.history['val_loss'], c='g', label='val_loss')
          
plt.legend()
          
plt.show()
      

picture.image


        
            

          model.summary()
        
      

picture.image

这是一个多输入多输出的 LSTM 模型,接受包含12个时间步长和3个特征的输入序列,在 经过一层128个神经元的 LSTM 层和两个全连接层后,输出三个单独的预测结果 ,分别是 meantemp、humidity 和 meanpressure

2.6 模型评价


          
from sklearn import metrics
          
y_pred = model.predict(test_x)
          
# 计算均方误差(MSE)
          
mse_meantemp = metrics.mean_squared_error(test_y[:,0], np.array([i for arr in y_pred[0] for i in arr]))
          
# 计算均方根误差(RMSE)
          
rmse_meantemp = np.sqrt(mse_meantemp)
          
# 计算平均绝对误差(MAE)
          
mae_meantemp = metrics.mean_absolute_error(test_y[:,0], np.array([i for arr in y_pred[0] for i in arr]))
          
from sklearn.metrics import r2_score # 拟合优度
          
r2_meantemp = r2_score(test_y[:,0], np.array([i for arr in y_pred[0] for i in arr]))
          
print("meantemp均方误差 (MSE):", mse_meantemp)
          
print("meantemp均方根误差 (RMSE):", rmse_meantemp)
          
print("meantemp平均绝对误差 (MAE):", mae_meantemp)
          
print("meantemp拟合优度:", r2_meantemp)
      

picture.image


          
mse_humidity = metrics.mean_squared_error(test_y[:,1], np.array([i for arr in y_pred[1] for i in arr]))
          
rmse_humidity = np.sqrt(mse_humidity)
          
mae_humidity = metrics.mean_absolute_error(test_y[:,1], np.array([i for arr in y_pred[1] for i in arr]))
          
r2_humidity = r2_score(test_y[:,1], np.array([i for arr in y_pred[1] for i in arr]))
          
print("humidity均方误差 (MSE):", mse_humidity)
          
print("humidity均方根误差 (RMSE):", rmse_humidity)
          
print("humidity平均绝对误差 (MAE):", mae_humidity)
          
print("humidity拟合优度:", r2_humidity)
      

picture.image


          
mse_meanpressure = metrics.mean_squared_error(test_y[:,2], np.array([i for arr in y_pred[2] for i in arr]))
          
rmse_meanpressure = np.sqrt(mse_meanpressure)
          
mae_meanpressure= metrics.mean_absolute_error(test_y[:,2], np.array([i for arr in y_pred[2] for i in arr]))
          
r2_meanpressure = r2_score(test_y[:,2], np.array([i for arr in y_pred[2] for i in arr]))
          
print("meanpressure均方误差 (MSE):", mse_meanpressure)
          
print("meanpressure均方根误差 (RMSE):", rmse_meanpressure)
          
print("meanpressure平均绝对误差 (MAE):", mae_meanpressure)
          
print("meanpressure拟合优度:", r2_meanpressure)
      

picture.image

2.7 模型向后预测


          
def predict_next_11_days(model, input_data):
          
    input_sequence = input_data.copy()
          
    
          
    # 预测未来 11 天的数据
          
    future_predictions = []
          
    for _ in range(11):
          
        predictions = model.predict(np.expand_dims(input_sequence[-1], axis=0))
          
        next_data = np.append(input_sequence[-1, 1:], np.array(predictions).reshape(1,3), axis=0)
          
        input_sequence = np.append(input_sequence, [next_data], axis=0)
          
        future_predictions.append(predictions)
          
    future_predictions = np.array(future_predictions).reshape(11, 3)
          

          
    return future_predictions
          

          
future_predictions = predict_next_11_days(model, test_x[-1:])
          
future_predictions
      

picture.image

2.8 预测可视化


          
# 反归一化
          
train_max_meantemp = np.max(df_train['meantemp'])
          
train_min_meantemp = np.min(df_train['meantemp'])
          
train_max_humidity = np.max(df_train['humidity'])
          
train_min_humidity = np.min(df_train['humidity'])
          
train_max_meanpressure = np.max(df_train['meanpressure'])
          
train_min_meanpressure = np.min(df_train['meanpressure'])
          

          
series_meantemp = np.array(future_predictions[:, 0])*(train_max_meantemp - train_min_meantemp)+train_min_meantemp
          
series_humidity = np.array(future_predictions[:, 1])*(train_max_humidity - train_min_humidity)+train_min_humidity
          
series_meanpressure = np.array(future_predictions[:, 2])*(train_max_meanpressure - train_min_meanpressure)+train_min_meanpressure
          

          
plt.figure(figsize=(20, 15), dpi =300)
          
plt.subplot(3,2,1)
          
plt.plot(pd.date_range(start='2013-01-13', end='2016-12-31', freq='D'), df_train.iloc[12::]['meantemp'],
          
         label='训练集', color='blue', alpha=0.8)
          
plt.plot(pd.date_range(start='2017-01-01', end='2017-04-24', freq='D'), df_test['meantemp'],
          
         label='测试集', color='gold', alpha=0.8)
          
plt.plot(pd.date_range(start='2017-01-13', end='2017-04-24', freq='D'),
          
         y_pred[0]*(train_max_meantemp-train_min_meantemp)+train_min_meantemp,
          
         label='测试集预测', color='navy', alpha=0.8)
          
plt.plot(pd.date_range(start='2017-04-24', end='2017-05-04', freq='D'),
          
         series_meantemp, label='向后预测10天', color='limegreen', alpha=0.8)
          
plt.legend()
          
plt.title('meantemp')
          
plt.grid(True)
          
plt.xlabel('time')
          
plt.ylabel('°C')
          
plt.subplot(3,2, 2)
          
plt.plot(pd.date_range(start='2017-01-01', end='2017-04-24', freq='D'), df_test['meantemp'],
          
         label='测试集', color='gold', alpha=0.8)
          
plt.plot(pd.date_range(start='2017-01-13', end='2017-04-24', freq='D'),
          
         y_pred[0]*(train_max_meantemp-train_min_meantemp)+train_min_meantemp,
          
         label='测试集预测', color='navy', alpha=0.8)
          
plt.plot(pd.date_range(start='2017-04-24', end='2017-05-04', freq='D'),
          
         series_meantemp, label='向后预测10天', color='limegreen', alpha=0.8)
          
plt.legend()
          
plt.title('meantemp')
          
plt.grid(True)
          
plt.xlabel('time')
          
plt.ylabel('°C')
          

          

          
plt.subplot(3,2,3)
          
plt.plot(pd.date_range(start='2013-01-13', end='2016-12-31', freq='D'), df_train.iloc[12::]['humidity'],
          
         label='训练集', color='blue', alpha=0.8)
          
plt.plot(pd.date_range(start='2017-01-01', end='2017-04-24', freq='D'), df_test['humidity'],
          
         label='测试集', color='gold', alpha=0.8)
          
plt.plot(pd.date_range(start='2017-01-13', end='2017-04-24', freq='D'),
          
         y_pred[1]*(train_max_humidity-train_min_humidity)+train_min_humidity,
          
         label='测试集预测', color='navy', alpha=0.8)
          
plt.plot(pd.date_range(start='2017-04-24', end='2017-05-04', freq='D'),
          
         series_humidity, label='向后预测10天', color='limegreen', alpha=0.8)
          
plt.legend()
          
plt.title('humidity')
          
plt.grid(True)
          
plt.xlabel('time')
          
plt.ylabel('°C')
          
plt.subplot(3,2,4)
          
plt.plot(pd.date_range(start='2017-01-01', end='2017-04-24', freq='D'), df_test['humidity'],
          
         label='测试集', color='gold', alpha=0.8)
          
plt.plot(pd.date_range(start='2017-01-13', end='2017-04-24', freq='D'),
          
         y_pred[1]*(train_max_humidity-train_min_humidity)+train_min_humidity,
          
         label='测试集预测', color='navy', alpha=0.8)
          
plt.plot(pd.date_range(start='2017-04-24', end='2017-05-04', freq='D'),
          
         series_humidity, label='向后预测10天', color='limegreen', alpha=0.8)
          
plt.legend()
          
plt.title('humidity')
          
plt.grid(True)
          
plt.xlabel('time')
          
plt.ylabel('°C')
          

          

          
plt.subplot(3,2,5)
          
plt.plot(pd.date_range(start='2013-01-13', end='2016-12-31', freq='D'), df_train.iloc[12::]['meanpressure'],
          
         label='训练集', color='blue', alpha=0.8)
          
plt.plot(pd.date_range(start='2017-01-01', end='2017-04-24', freq='D'), df_test['meanpressure'],
          
         label='测试集', color='gold', alpha=0.8)
          
plt.plot(pd.date_range(start='2017-01-13', end='2017-04-24', freq='D'),
          
         y_pred[2]*(train_max_meanpressure-train_min_meanpressure)+train_min_meanpressure,
          
         label='测试集预测', color='navy', alpha=0.8)
          
plt.plot(pd.date_range(start='2017-04-24', end='2017-05-04', freq='D'),
          
         series_meanpressure, label='向后预测10天', color='limegreen', alpha=0.8)
          
plt.legend()
          
plt.title('meanpressure')
          
plt.grid(True)
          
plt.xlabel('pa')
          
plt.ylabel('°C')
          
plt.subplot(3,2,6)
          
plt.plot(pd.date_range(start='2017-01-01', end='2017-04-24', freq='D'), df_test['meanpressure'],
          
         label='测试集', color='gold', alpha=0.8)
          
plt.plot(pd.date_range(start='2017-01-13', end='2017-04-24', freq='D'),
          
         y_pred[2]*(train_max_meanpressure-train_min_meanpressure)+train_min_meanpressure,
          
         label='测试集预测', color='navy', alpha=0.8)
          
plt.plot(pd.date_range(start='2017-04-24', end='2017-05-04', freq='D'),
          
         series_meanpressure, label='向后预测10天', color='limegreen', alpha=0.8)
          
plt.legend()
          
plt.title('meanpressure')
          
plt.grid(True)
          
plt.xlabel('time')
          
plt.ylabel('pa')
          
plt.show()
      

picture.image

3.**** 往期推荐

使用LSTM模型预测多特征变量的时间序列

TCN时间序列卷积神经网络

基于VMD分解的VMD-CNN-LSTM时间序列预测模型实现

基于VMD分解的VMD-LSTM时间序列预测模型实现,大力提升预测精度!

ARIMA模型进阶——具有季节性的SARIMAX模型实现

时间序列——移动平均(SMA、EMA、WMA)

时间序列——平稳性检验

时间序列——季节性检验

长短期记忆网络LSTM在时序数据预测演示

如果你对类似于这样的文章感兴趣。

欢迎关注、点赞、转发~

0
0
0
0
评论
未登录
暂无评论