时间序列预测 — LSTM实现多变量多步负荷预测(Tensorflow):多输入多输出

news2025/1/11 14:51:39

目录

1 数据处理

1.1 导入库文件

1.2 导入数据集

​1.3 缺失值分析

2 构造训练数据

3 LSTM模型训练

4 LSTM模型预测

4.1 分量预测

4.2 可视化


1 数据处理

1.1 导入库文件

import time
import datetime
import pandas as pd 
import numpy as np 
import matplotlib.pyplot as plt  
from sampen import sampen2  # sampen库用于计算样本熵
from vmdpy import VMD  # VMD分解库
from itertools import cycle

import tensorflow as tf 
from sklearn.cluster import KMeans
from sklearn.metrics import r2_score, mean_squared_error, mean_absolute_error, mean_absolute_percentage_error 
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Activation, Dropout, LSTM, GRU, Reshape, BatchNormalization
from tensorflow.keras.callbacks import ReduceLROnPlateau, EarlyStopping, ModelCheckpoint
from tensorflow.keras.optimizers import Adam

# 忽略警告信息
import warnings
warnings.filterwarnings('ignore'))  
plt.rcParams['font.sans-serif'] = ['SimHei']     # 显示中文
plt.rcParams['axes.unicode_minus'] = False  # 显示负号
plt.rcParams.update({'font.size':18})  #统一字体字号

1.2 导入数据集

实验数据集采用数据集6:澳大利亚电力负荷与价格预测数据(下载链接),包括数据集包括日期、小时、干球温度、露点温度、湿球温度、湿度、电价、电力负荷特征,时间间隔30min。

from itertools import cycle
# 可视化数据
def visualize_data(data, row, col):
    cycol = cycle('bgrcmk')
    cols = list(data.columns)
    fig, axes = plt.subplots(row, col, figsize=(16, 4))
    fig.tight_layout()
    if row == 1 and col == 1:  # 处理只有1行1列的情况
        axes = [axes]  # 转换为列表,方便统一处理
    for i, ax in enumerate(axes.flat):
        if i < len(cols):
            ax.plot(data.iloc[:,i], c=next(cycol))
            ax.set_title(cols[i])
        else:
            ax.axis('off')  # 如果数据列数小于子图数量,关闭多余的子图
    plt.subplots_adjust(hspace=0.6)
    plt.show()

visualize_data(data_raw.iloc[:,2:], 2, 3)

单独查看部分负荷数据,发现有较强的规律性。

​1.3 缺失值分析

首先查看数据的信息,发现并没有缺失值

data_raw.info()

进一步统计缺失值

data_raw.isnull().sum()

2 构造训练数据

构造数据前先将数据变为数值类型

data_load = data_raw.iloc[:,2:].values

构造训练数据,也是真正预测未来的关键。首先设置预测的timesteps时间步、predict_steps预测的步长(预测的步长应该比总的预测步长小),length总的预测步长,参数可以根据需要更改。

timesteps = 48*7 #构造x,为72个数据,表示每次用前72个数据作为一段
predict_steps = 6 #构造y,为12个数据,表示用后12个数据作为一段
length = 48 #预测多步,预测96个数据,每次预测96个,想想要怎么构造预测才能满足96?
feature_num = 6 #特征个数

通过前timesteps行历史数据预测后面predict_steps个数据,需要对数据集进行滚动划分(也就是前timesteps行的数据和后predict_steps行的数据训练,后面预测时就可通过timesteps行数据预测未来的predict_steps行数据)。这里需要注意的是,因为是多变量预测多变量,特征就是标签(例如,前5行[干球温度、露点温度、湿球温度、电价、电力负荷]预测第6行[干球温度、露点温度、湿球温度、电价、电力负荷],划分数据集时,就用前5行当做train_x,第6行作为train_y,此时的train_y有多列,而不是只有1列)。

# 构造数据集,用于真正预测未来数据
# 整体的思路也就是,前面通过前timesteps个数据训练后面的predict_steps个未来数据
# 预测时取出前timesteps个数据预测未来的predict_steps个未来数据。
def create_dataset(datasetx, datasety=None, timesteps=96*7, predict_size=12):
    datax = []  # 构造x
    datay = []  # 构造y
    for each in range(len(datasetx) - timesteps - predict_size):
        x = datasetx[each:each + timesteps]
        # 判断是否是单变量分解还是多变量分解
        if datasety is not None:
            y = datasety[each + timesteps:each + timesteps + predict_size]
        else:
            y = datasetx[each + timesteps:each + timesteps + predict_size]
        datax.append(x)
        datay.append(y)
    return datax, datay

​数据处理前,需要对数据进行归一化,按照上面的方法划分数据,这里返回划分的数据和归一化模型(变量和多变量的归一化不同,多变量归一化需要将X和Y分开归一化,不然会出现信息泄露的问题),此时的归一化相当于是单变量归一化,函数的定义如下:

# 数据归一化操作
def data_scaler(datax, datay=None, timesteps=36, predict_steps=6):
    # 数据归一化操作
    scaler1 = MinMaxScaler(feature_range=(0, 1))   
    datax = scaler1.fit_transform(datax)
    # 用前面的数据进行训练,留最后的数据进行预测
    # 判断是否是单变量分解还是多变量分解
    if datay is not None:
        scaler2 = MinMaxScaler(feature_range=(0, 1))
        datay = scaler2.fit_transform(datay)
        trainx, trainy = create_dataset(datax, datay, timesteps, predict_steps)
        trainx = np.array(trainx)
        trainy = np.array(trainy)
        return trainx, trainy, scaler1, scaler2
    else:
        trainx, trainy = create_dataset(datax, timesteps=timesteps, predict_size=predict_steps)
        trainx = np.array(trainx)
        trainy = np.array(trainy)
        return trainx, trainy, scaler1, None

然后分解的数据进行划分和归一化。通过前7天的48*7行数据预测后1天的数据48个,需要对数据集进行滚动划分(也就是前48*7行的数据和后6行的数据训练,后面预测时就可通过48*7行数据测未来的6行标签,然后将6行预测值添加到历史数据中,历史数据变为48*7+6个,再取出后48*7行数据进行预测,得到6行预测值,滚动进行预测直到预测完成,注意此时的预测值是行而不是个)

trainx, trainy, scalerx, scalery = data_scaler(data_load, timesteps=timesteps, predict_steps=predict_steps)

3 LSTM模型训练

首先划分训练集、测试集、验证数据:

train_x = trainx[:int(trainx.shape[0] * 0.8)]
train_y = trainy[:int(trainy.shape[0] * 0.8)]
test_x = trainx[int(trainx.shape[0] * 0.8):]
test_y = trainy[int(trainy.shape[0] * 0.8):]
test_x.shape, test_y.shape, train_x.shape, train_y.shape

首先搭建模型的常规操作,然后使用训练数据trainx和trainy进行训练,进行50个epochs的训练,每个batch包含64个样本(建议使用GPU进行训练)。

# 搭建LSTM训练函数
def LSTM_model_train(trainx, trainy, valx, valy, timesteps, predict_steps):
    # 调用GPU加速
    gpus = tf.config.experimental.list_physical_devices(device_type='GPU')
    for gpu in gpus:
        tf.config.experimental.set_memory_growth(gpu, True)

    # 搭建LSTM模型
    start_time = datetime.datetime.now()
    model = Sequential()
    model.add(LSTM(128, input_shape=(timesteps, trainx.shape[2]), return_sequences=True))
    model.add(BatchNormalization())  # 添加BatchNormalization层
    model.add(Dropout(0.2))
    model.add(LSTM(64, return_sequences=False))
    model.add(Dense(predict_steps * trainy.shape[2]))
    model.add(Reshape((predict_steps, trainy.shape[2])))

    # 使用自定义的Adam优化器
    opt = Adam(learning_rate=0.001)
    model.compile(loss="mean_squared_error", optimizer=opt)
    
    # 添加早停和模型保存的回调函数
    es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=10)
    mc = ModelCheckpoint('best_model.h5', monitor='val_loss', mode='min', save_best_only=True)

    # 训练模型,这里我假设你有一个验证集(valx, valy)
    history = model.fit(trainx, trainy, validation_data=(valx, valy), epochs=50, batch_size=64, callbacks=[es, mc])

    # 记录训练损失
    loss_history = history.history['loss']

    end_time = datetime.datetime.now()
    running_time = end_time - start_time

    return model, loss_history, running_time

然后进行训练,将训练的模型、损失和训练时间保存。

#模型训练
model, loss_history, running_time = LSTM_model_train(train_x, train_y, test_x, test_y, timesteps, predict_steps)
# 将模型保存为文件
model.save('lstm_model.h5')

训练损失可视化

plt.figure(dpi=100, figsize=(14, 5))
plt.plot(loss_history, markevery=5)

4 LSTM模型预测

4.1 分量预测

下面介绍文章中最重要,也是真正没有未来特征的情况下预测未来标签的方法。整体的思路也就是取出预测前48*7行数据预测未来的6行数据,然后见6行数据添加进历史数据,再预测6行数据,滚动预测。因为每次只能预测6行数据,但是我要预测48个数据,所以采用的就是循环预测的思路。每次预测的6行数据,添加到数据集中充当预测x,然后在预测新的6行y,再添加到预测x列表中,如此往复,最终预测出48行。(注意多变量预测多变量预测的是多列,预测单变量只有一列)

# #滚动predict
# #因为每次只能预测6个数据,但是我要预测6个数据,所以采用的就是循环预测的思路。
# #每次预测的6个数据,添加到数据集中充当预测x,然后在预测新的6个y,再添加到预测x列表中,如此往复,最终预测出48个点。
def predict_using_LSTM(model, data, timesteps, predict_steps, feature_num, length, scaler):
    predict_xlist = np.array(data).reshape(1, timesteps, feature_num) 
    predict_y = np.array([]).reshape(0, feature_num)  # 初始化为空的二维数组
    print('predict_xlist', predict_xlist.shape)
    
    while len(predict_y) < length:
        # 从最新的predict_xlist取出timesteps个数据,预测新的predict_steps个数据
        predictx = predict_xlist[:,-timesteps:,:]
        # 变换格式,适应LSTM模型
        predictx = np.reshape(predictx, (1, timesteps, feature_num)) 
        print('predictx.shape', predictx.shape)
        
        # 预测新值
        lstm_predict = model.predict(predictx)
        print('lstm_predict.shape', lstm_predict.shape)
        
        # 滚动预测
        # 将新预测出来的predict_steps个数据,加入predict_xlist列表,用于下次预测
        print('predict_xlist.shape', predict_xlist.shape)
        predict_xlist = np.concatenate((predict_xlist, lstm_predict), axis=1)
        print('predict_xlist.shape', predict_xlist.shape)
        
        # 预测的结果y,每次预测的6行数据,添加进去,直到预测length个为止
        lstm_predict = scaler.inverse_transform(lstm_predict.reshape(predict_steps, feature_num))
        predict_y = np.concatenate((predict_y, lstm_predict), axis=0)
        print('predict_y', predict_y.shape)
        
    return predict_y

然后对数据进行预测,得到预测结果。

from tensorflow.keras.models import load_model
model = load_model('best_model.h5')
pre_x = scalerx.fit_transform(data_load[-48*8:-48])
pre_y = data_load[-48:,-1]
y_predict = predict_using_LSTM(model, pre_x, timesteps, predict_steps, feature_num, length, scalerx)

4.2 可视化

对预测的结果进行可视化并计算误差。

# 预测并计算误差和可视化
def error_and_plot(y_true,y_predict):
    # 计算误差
    r2 = r2_score(y_true, y_predict)
    rmse = mean_squared_error(y_true, y_predict, squared=False)
    mae = mean_absolute_error(y_true, y_predict)
    mape = mean_absolute_percentage_error(y_true, y_predict)
    print("r2: %.2f\nrmse: %.2f\nmae: %.2f\nmape: %.2f" % (r2, rmse, mae, mape))
    
    # 预测结果可视化
    cycol = cycle('bgrcmk')
    plt.figure(dpi=100, figsize=(14, 5))
    plt.plot(y_true, c=next(cycol), markevery=5)
    plt.plot(y_predict, c=next(cycol), markevery=5)
    plt.legend(['y_true', 'y_predict'])
    plt.xlabel('时间')
    plt.ylabel('功率(kW)')
    plt.show()   
    
    return 0
error_and_plot(pre_y, y_predict[:,-1]) 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1361889.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++八股学习心得.6

1.C 异常处理 异常是程序在执行期间产生的问题。C 异常是指在程序运行时发生的特殊情况 异常提供了一种转移程序控制权的方式。C 异常处理涉及到三个关键字&#xff1a;try、catch、throw。 throw: 当问题出现时&#xff0c;程序会抛出一个异常。这是通过使用 throw 关键字来…

给Flutter + FireBase 增加 badge 徽章,App启动器 通知红点。

在此之前需要配置好 firebase 在flutter 在项目中。&#xff08;已经配置好的可以忽略此提示&#xff09; Firebase 配置教程&#xff1a;flutter firebase 云消息通知教程 (android-安卓、ios-苹果)_flutter firebase_messaging ios环境配置-CSDN博客 由于firebase 提供的消息…

3D空间漫游技术的日趋成熟,让博物馆数字化大放异彩!

随着科技的飞速发展&#xff0c;互联网已经成为人们生活中不可或缺的一部分。在这个数字化时代&#xff0c;博物馆也紧跟时代潮流&#xff0c;将传统的实体博物馆与现代科技相结合&#xff0c;诞生了一种全新的博物馆形式——3D线上博物馆。这种新型博物馆凭借其独特的魅力&…

RT_Thread 调试笔记:串口打印、MSH控制台 相关

说明&#xff1a;记录日常使用 RT_Thread 开发时做的笔记。 持续更新中&#xff0c;欢迎收藏。 1.打印相关 1.打印宏定义&#xff0c;可以打印打印所在文件&#xff0c;函数&#xff0c;行数。 #define PRINT_TRACE() printf("-------%s:%s:%d------\r\n", __FIL…

宏电股份5G RedCap终端产品助力深圳极速先锋城市建设

12月26日&#xff0c;“全城全网&#xff0c;先锋物联”深圳移动5G-A RedCap助力深圳极速先锋城市创新发布会举行&#xff0c;宏电股份携一系列5G RedCap终端产品应邀参与创新发布会&#xff0c;来自全国5G生态圈的各界嘉宾、专家学者济济一堂&#xff0c;共探信息化数字化创新…

GitHub 一周热点汇总 第4期 (2024/01/01-01/06)

GitHub一周热点汇总第四期 (2023/12/24-12/30)&#xff0c;梳理每周热门的GitHub项目&#xff0c;了解热点技术趋势&#xff0c;掌握前沿科技方向&#xff0c;发掘更多商机。2024年到了&#xff0c;希望所有的朋友们都能万事顺遂。 说明一下&#xff0c;有时候本周的热点项目会…

蟹目标检测数据集VOC格式400张

蟹&#xff0c;一种独特的海洋生物&#xff0c;以其强壮的身体和独特的生活习性而闻名。 蟹的身体宽厚&#xff0c;有一对锐利的大钳子&#xff0c;这使得它们在寻找食物和保护自己时非常有力。蟹的外观颜色多样&#xff0c;有绿色、蓝色、棕色和红色等&#xff0c;这使得它们在…

软件工程概论------文件管理

目录 1.文件的相关概念 2.文件目录 3.位示图 4.索引文件 5.例题 1.文件的相关概念 文件:具有符号名的、在逻辑上具有完整意义的一组相关信息项的集合。 逻辑结构:有结构的记录式文件、无结构的流式文件。 物理结构: 连续结构、链接结构、索引结构、多个物理块的索引表。 …

解决ChatGPT4.0无法上传文件

问题描述 ChatGPT4.0&#xff1a;上传文件时出错 解决方案&#xff1a; 仔细检查文件的编码格式&#xff0c;他似乎目前只能接受utf-8的编码&#xff0c;所以把文件的编码改为UTF-8即可成功上传

企业Aspera替代方案有哪些推荐

随着企业数据量的不断增加&#xff0c;数据传输和共享成为了一个重要的问题。Aspera是一款高性能、低延迟的数据传输工具&#xff0c;但是它并不是万能的&#xff0c;随着数据量的不断增大&#xff0c;也有一些企业需要寻找Aspera的替代方案。本文将介绍三种常用的企业Aspera替…

物联网的感知层、网络层与应用层分享

物联网的概念在很早以前就已经被提出&#xff0c;20世纪末期在美国召开的移动计算和网络国际会议就已经提出了物联网(Internet of Things)这个概念。 最先提出这个概念的是MIT Auto-ID中心的Ashton教授&#xff0c;他在研究RFID技术时&#xff0c;便提出了结合物品编码、互联网…

如何在群晖7.2中运行WPS Office镜像容器并使用固定地址公网访问

文章目录 1. 拉取WPS Office镜像2. 运行WPS Office镜像容器3. 本地访问WPS Office4. 群晖安装Cpolar5. 配置WPS Office远程地址6. 远程访问WPS Office小结 7. 固定公网地址 wps-office是一个在Linux服务器上部署WPS Office的镜像。它基于WPS Office的Linux版本&#xff0c;通过…

AI硬件2——SIPEED MaixCube(Kendryte K210)基础使用

系列文章目录 官方网站 开发文档 文章目录 系列文章目录前言一、特点介绍1、MaixPy2、KPU3、MaixPy IDE4、kmodel 二、环境准备1、USB 驱动安装1&#xff09;Linux2&#xff09;Windows 2、更新固件3、串口工具1&#xff09;连接硬件2&#xff09;Windows串口工具3&#xff09…

「优质Verilog刷题网站推荐」HDLBits

目前 集成电路领域算是风口行业之一 因此需要大量的芯片设计人才 而数字集成电路是其中的前端部分 设计数字集成电路所使用的主流语言是Verilog 然而 不像传统的编程语言C Java Python等有大量的刷题网站如力扣、牛客网等 支持Verilog刷题的网站不算很多 优质的就更少了 牛客网…

精选顶级期刊中的三幅可复现图表

简介 最近在阅读文献时&#xff0c;发现了一些出色的可视化案例&#xff0c;特此与大家分享。这些图共同的特点是&#xff1a;1. 易懂明晰&#xff1b; 2. 信息丰富&#xff1b; 3. 配色优雅。 小编有话说&#xff1a;以下三幅图选自领域内顶级期刊&#xff0c;虽然并非采用R语…

【ChatGPT】提示设计的艺术:使用清晰的语法

探索清晰的语法如何使您能够将意图传达给语言模型&#xff0c;并帮助确保输出易于解析 All images were generated by Scott and Marco. 这是与Marco Tulio Ribeiro共同撰写的关于如何使用指导来控制大型语言模型&#xff08;LLM&#xff09;的系列文章的第一部分。我们将从基…

快速了解云计算与云原生

快速了解云计算与云原生 云计算云原生DevOps容器持续交付微服务 云计算 在讲云原生之前&#xff0c;先来讲讲云计算 其中云原生属于技术架构理念&#xff0c;而云计算提供应用所需的基础资源&#xff0c;云计算是云原生的基础&#xff0c;两者是相辅相成的 云计算简单来说&a…

2024--Django平台开发-Web框架和Django基础(二)

day02 Web框架和Django基础 今日概要&#xff1a; 网络底层引入&#xff0c;到底什么是web框架&#xff1f;常见web框架对比django快速上手&#xff08;创建网站&#xff09;常见操作&#xff1a;虚拟环境、django项目、多app应用、纯净版逐点剖析&#xff1a;路由、视图、模…

SpringBoot基于Redis(7.2)分片集群实现读写分离

文章目录 一、前置提要二、集群搭建三、SpringBoot访问分片集群 一、前置提要 SpringBoot访问Redis分片集群和Redis哨兵模式&#xff0c;使用上没有什么区别。唯一的区别在于application.yml配置上不一样。 二、集群搭建 首先&#xff0c;无论如何&#xff0c;得先有一个Red…

零配置,零麻烦:MapStruct 的轻松对象映射之旅

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 零配置&#xff0c;零麻烦&#xff1a;MapStruct 的轻松对象映射之旅 前言MapStruct是什么快速上手&#xff1a;基础映射高级映射技巧1. 针对复杂类型的映射&#xff1a;2. 自定义映射逻辑&#xff1a…