基于pytorch搭建多特征LSTM时间序列预测代码详细解读(附完整代码)

news2024/11/25 16:18:58

文章目录

  • LSTM时间序列预测
    • 数据获取与预处理
    • 模型构建
    • 训练与测试

LSTM时间序列预测

对于LSTM神经网络的概念想必大家也是熟练掌握了,所以本文章不涉及对LSTM概念的解读,仅解释如何使用pytorch使用LSTM进行时间序列预测,复原使用代码实现的全流程。

数据获取与预处理

首先预览一下本次实验使用的数据集,该数据集共有三个特征,将最后一列的压气机出口温度作为标签预测(该数据集是我在git上收集到的)
数据集

定义一个xls文件读取的函数,其中data.iloc()函数是将dataframe中的数据进行切片,返回数据和标签

# 文件读取
def get_Data(data_path):

    data=pd.read_excel(data_path)
    data=data.iloc[:,:3]  # 以三个特征作为数据
    label=data.iloc[:,2:] # 取最后一个特征作为标签
    print(data.head())
    print(label.head())
    return data,label

使用sklearn中的preprocessing模块中的归一化函数对数据进行归一化处理,其中data=data.values函数是将dataframe中的数据从pd格式转换np数组,删除轴标签,fit_transform函数是fit()和transform()的组合,是将fit和transform合并,一步到位的结果,最后返回data,label和归一化的标签值

# 数据预处理
def normalization(data,label):

    mm_x=MinMaxScaler() # 导入sklearn的预处理容器
    mm_y=MinMaxScaler()
    data=data.values    # 将pd的系列格式转换为np的数组格式
    label=label.values
    data=mm_x.fit_transform(data) # 对数据和标签进行归一化等处理
    label=mm_y.fit_transform(label)
    return data,label,mm_y

我们将数据进行归一化之后,数据是np数组格式,我们需要将其转换成向量的格式存储在列表当中,因此,先创建两个空列表,建立一个for循环将预处理过的数据最后按x.size(0),seq_length,features)的纬度输出至列表当中。其中seq_length代表的是时间步长,x.size(0)则表示的是数据的第一维度,features代表的是数据的特征数。打印x,y的维度并返回x,y。

# 时间向量转换
def split_windows(data,seq_length):

    x=[]
    y=[]
    for i in range(len(data)-seq_length-1): # range的范围需要减去时间步长和1
        _x=data[i:(i+seq_length),:]
        _y=data[i+seq_length,-1]
        x.append(_x)
        y.append(_y)
    x,y=np.array(x),np.array(y)
    print('x.shape,y.shape=\n',x.shape,y.shape)
    return x,y

将数据和标签都准备好之后即可分离数据,将数据分离成训练集和测试集。定义split_data()函数,其中split_ratio是设定的测试集比例,本次实验设置的训练集与测试集之比为9:1,即split_ratio=0.1。将分离好的数据分别装入Variable中封装好,并且将array转换成tensor格式,得到测试集和训练集。注意,一定要使用Variable函数对数据集进行封装,否则不支持后面torch的迭代。

# 数据分离
def split_data(x,y,split_ratio):

    train_size=int(len(y)*split_ratio)
    test_size=len(y)-train_size

    x_data=Variable(torch.Tensor(np.array(x)))
    y_data=Variable(torch.Tensor(np.array(y)))

    x_train=Variable(torch.Tensor(np.array(x[0:train_size])))
    y_train=Variable(torch.Tensor(np.array(y[0:train_size])))
    y_test=Variable(torch.Tensor(np.array(y[train_size:len(y)])))
    x_test=Variable(torch.Tensor(np.array(x[train_size:len(x)])))

    print('x_data.shape,y_data.shape,x_train.shape,y_train.shape,x_test.shape,y_test.shape:\n{}{}{}{}{}{}'
    .format(x_data.shape,y_data.shape,x_train.shape,y_train.shape,x_test.shape,y_test.shape))

    return x_data,y_data,x_train,y_train,x_test,y_test

将封装好的训练集和测试集装入torch支持的可迭代对象torch.utils.data.DataLoader中,num_epochs是计算得到的迭代次数,返回train_loader,test_loader,num_epochs,这样,数据集就预处理好了,可以进行模型的搭建了。

# 数据装入
def data_generator(x_train,y_train,x_test,y_test,n_iters,batch_size):

    num_epochs=n_iters/(len(x_train)/batch_size) # n_iters代表一次迭代
    num_epochs=int(num_epochs)
    train_dataset=Data.TensorDataset(x_train,y_train)
    test_dataset=Data.TensorDataset(x_test,y_test)
    train_loader=torch.utils.data.DataLoader(dataset=train_dataset,batch_size=batch_size,shuffle=False,drop_last=True) # 加载数据集,使数据集可迭代
    test_loader=torch.utils.data.DataLoader(dataset=test_dataset,batch_size=batch_size,shuffle=False,drop_last=True)

    return train_loader,test_loader,num_epochs

模型构建

使用torch构建模型无非就是定义一个类,在这个类中定义一个模型实例和前向传播函数,就这么简单,接下来让我们来看看。

# 定义一个类
class Net(nn.Module):
    def __init__(self,input_size,hidden_size,num_layers,output_size,batch_size,seq_length) -> None:
        super(Net,self).__init__()
        self.input_size=input_size
        self.hidden_size=hidden_size
        self.num_layers=num_layers
        self.output_size=output_size
        self.batch_size=batch_size
        self.seq_length=seq_length
        self.num_directions=1 # 单向LSTM

        self.lstm=nn.LSTM(input_size=input_size,hidden_size=hidden_size,num_layers=num_layers,batch_first=True) # LSTM层
        self.fc=nn.Linear(hidden_size,output_size) # 全连接层

    def forward(self,x):
        # e.g.  x(10,3,100) 三个句子,十个单词,一百维的向量,nn.LSTM(input_size=100,hidden_size=20,num_layers=4)
        # out.shape=(10,3,20) h/c.shape=(4,b,20)
        batch_size, seq_len = x.size()[0], x.size()[1]    # x.shape=(604,3,3)
        h_0 = torch.randn(self.num_directions * self.num_layers, x.size(0), self.hidden_size)
        c_0 = torch.randn(self.num_directions * self.num_layers, x.size(0), self.hidden_size)
        # output(batch_size, seq_len, num_directions * hidden_size)
        output, _ = self.lstm(x, (h_0, c_0)) # output(5, 30, 64)
        pred = self.fc(output)  # (5, 30, 1)
        pred = pred[:, -1, :]  # (5, 1)
        return pred

首先定义一个实例,其中包括必须参数input_size,hidden_size,num_layers,output_size,batch_size,seq_length。将self.num_directions设置为1代表这是一个单项的LSTM,然后再添加一个lstm层和一个全连接层fc,lstm层输入维度为(input_size=input_size,hidden_size=hidden_size,num_layers=num_layers),设置了,batch_first=True则代表shape=(batch_size,seq_size,hidden_size),fc层的参数为(hidden_size,output_size),返回pred

训练与测试

训练模型,初始化i,(batch_x, batch_y),将train_loader设置为枚举类型,optimizer.zero_grad() 代表将每次传播时的梯度累积清除,torch中如果不声明optimizer.zero_grad()则会一直累积计算梯度,设置每100次输入打印一次损失

# train
iter=0
for epochs in range(num_epochs):
  for i,(batch_x, batch_y) in enumerate (train_loader):
    outputs = moudle(batch_x)
    optimizer.zero_grad()   # 将每次传播时的梯度累积清除
    # print(outputs.shape, batch_y.shape)
    loss = criterion(outputs,batch_y) # 计算损失
    loss.backward() # 反向传播
    optimizer.step()
    iter+=1
    if iter % 100 == 0:
      print("iter: %d, loss: %1.5f" % (iter, loss.item()))

最后几次损失如下

iter: 2400, loss: 0.00331
iter: 2500, loss: 0.00039
...
iter: 4400, loss: 0.00332
iter: 4500, loss: 0.00022
iter: 4600, loss: 0.00380
iter: 4700, loss: 0.00032

将最后训练集和测试集的MAE/RMSE画出,得到最终结果。

def result(x_data, y_data):
  moudle.eval()
  train_predict = moudle(x_data)

  data_predict = train_predict.data.numpy()
  y_data_plot = y_data.data.numpy()
  y_data_plot = np.reshape(y_data_plot, (-1,1))  
  data_predict = mm_y.inverse_transform(data_predict)
  y_data_plot = mm_y.inverse_transform(y_data_plot)

  plt.plot(y_data_plot)
  plt.plot(data_predict)
  plt.legend(('real', 'predict'),fontsize='15')
  plt.show()

  print('MAE/RMSE')
  print(mean_absolute_error(y_data_plot, data_predict))
  print(np.sqrt(mean_squared_error(y_data_plot, data_predict) ))

result(x_data, y_data)
result(x_test,y_test)

在这里插入图片描述
在这里插入图片描述
最终结果:训练集:MAE/RMSE:35.114613\75.8706
测试集:MAE/RMSE:213.30313\213.31061
本文仅作示范pytorch构建lstm的用法,预测结果不是很准确,像dropout等都没加,仅供参考。
完整代码见我的github:https://github.com/Tuniverj/Pytorch-lstm-forecast

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

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

相关文章

【Python实战】Python采集小说文本内容

前言 今天,我们将采集某小说数据,通过这个案例,加深我们对正则表达式的理解。我们今天来通过使用正则表达式来获取我们想要的文本。 环境使用 python 3.9pycharm模块使用 requests模块介绍 requests requests是一个很实用的Python HTTP客户端库,爬虫和测试服务器响应…

MaxScript的Shape相关操作例子

MaxScript学习笔记目录 大家好,我是阿赵。之前有网友私信问了我一个相关的问题,我发现之前漏了MaxScript里面的Shape的内容,所以补一个例子,当做一个记录吧。 一、例子说明 这里做一个关于MaxScript读取二维形状(Shape)数据的例…

加盐加密——保障你的数据安全

目录 今日良言:理性和激情是生活不可或缺的调味品 一、加盐加密 1.普通密码的缺点 2.什么是加盐加密 3.加盐加密的过程 4.加盐加密的实现 今日良言:理性和激情是生活不可或缺的调味品 一、加盐加密 1.普通密码的缺点 在介绍加盐加密之前,先想想为什么普通密…

STM32F4_指针(单片机)

目录 前言 1. 计算机存储机制 2. 定义指针 2.1 指针操作 2.2 数组与指针 前言 指针(Pointer)是C语言的一个重要知识点,其使用灵活、功能强大,是C语言的灵魂。指针与底层硬件联系密切,使用指针可操作数据的地址,实现数据的间…

PreSumm模型

Text Summarization with Pretrained Encoders(PreSumm模型) 论文地址 摘要 在本文中,我们展示了如何在文本摘要中有效地应用BERT,并为提取性模型和抽象模型提出了一个通用框架。我们介绍了基于BERT的新颖文档级编码器&#xf…

安装VMware Workstation和虚拟机教程

一、VM简介   VMware Workstation中文版是一个“虚拟 PC”软件。它使你可以在一台机器上同时运行二个或更多 Windows、DOS、LINUX 系统。与“多启动”系统相比,VMWare 采用了完全不同的概念。多启动系统在一个时刻只能运行一个系统,在系统切换时需要重…

iPad Pro “买后生产力” - 在iPad上远程连接服务器编程写代码【公网远程】

文章目录 前言视频教程1. 本地环境配置2. 内网穿透2.1 安装cpolar内网穿透(支持一键自动安装脚本)2.2 创建HTTP隧道 3. 测试远程访问4. 配置固定二级子域名4.1 保留二级子域名4.2 配置二级子域名 5. 测试使用固定二级子域名远程访问6. iPad通过软件远程vscode6.1 创建TCP隧道 7…

sprintboot logback高级特性使用

一、业务需求 日志级别的分类 日志的级别分为: trace:微量,少许的意思,级别最低info:普通的打印信息debug:需要调试时候的关键信息打印warn:警告,不影响使⽤,但需要注…

Socket(四)

文章目录 1. 服务器Socket简介2. 使用ServerSocket3. 用Socket写入服务器4. 关闭服务器Socket 1. 服务器Socket简介 博客Socket(一)~Socket(二)从客户端的角度讨论了Socket,客户端就是向监听连接的服务器打…

Git基本概念

Git基础 git 介绍git工作流程 git 介绍 1、git是什么:是目前世界上最先进的分布式版本控制系统 2、git的优势 ● 适合分布式开发、强调个体。 ● 公共服务器压力和数量都不会太大 ● 速度快、灵活 ● 任意两个开发者之间可以很容易的解决冲突 ● 离线工作 3、git能…

华为OD机试真题B卷 Java 实现【乱序整数序列两数之和绝对值最小】,附详细解题思路

一、题目描述 给定一个随机的整数(可能存在正整数和负整数)数组 nums,请你在该数组中找出两个数,其和的绝对值(|nums[x]nums[y]|)为最小值,并返回这个两个数(按从小到大返回)以及绝对值。 每种…

全志V3S嵌入式驱动开发(网卡驱动)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 一开始上来就说网卡,好像有点不太对劲。这主要是因为如果开发板可以连接网络的话,可以帮我们节约很多的时间,开…

逍遥自在学C语言 | 揭开while循环的神秘面纱

前言 循环是一种重要的控制结构,可以使程序重复执行一段代码,直到满足特定条件为止。 在C语言中,while和do-while是两种常用的循环结构,本文将详细介绍这两种循环的用法。 一、人物简介 第一位闪亮登场,有请今后会一…

eclipse安装lombok插件

项目中遇到了一些实体类声明了属性,缺少get/set方法,但是类上使用了Getter 和 Setter注解,查了下是lombok插件的强大功能。 这里先不看lombok的功能,先看下eclipse安装lombok插件的过程。 1、 https://projectlombok.org/downlo…

三十五、数学知识——快速幂(反复平方法 + 快速幂求逆元)

快速幂算法主要内容 一、基本原理1、概念 暴力求解2、核心原理——反复平方法3、快速幂求逆元 二、Java、C语言模板实现三、例题题解 一、基本原理 1、概念 暴力求解 问题目标: 快速求出 a^k mod p 的结果,时间复杂度为 O(logk),其中 a,p…

华为OD机试真题B卷 Java 实现【字符串变换最小字符串】,附详细解题思路

一、题目描述 给定一个字符串s,最多只能进行一次变换,返回变换后能得到的最小字符串(按照字典序进行比较)。 变换规则:交换字符串中任意两个不同位置的字符。 二、输入描述 一串小写字母组成的字符串s。 三、输出…

人工智能-不确定性的量化

这一部分的重点内容有: 贝叶斯规则贝叶斯网络基于隐马尔可夫模型的概率推理 大概会有以下几种考察形式,有答案的历年期末考试题只解释一些注意的地方 贝叶斯网络-独立性 第二问答案很详细,第一问看↓ D-separation: 判断贝叶…

Stable-diffusion-webui 本地部署及使用

Stable-diffusion-webui 本地部署及使用 本地部署stable-diffusion-webui(windows)1.安装conda;2.创建conda env 和python 3.10.6;3.更新pip;4.安装cuda 11.8;5.克隆stable-diffusion-webui仓库 ;6.下载SD模型7.运行sd…

Dubbo配置

dubbo配置官网参考 1.配置原则 JVM 启动 -D 参数优先,这样可以使用户在部署和启动时进行参数重写,比如在启动时需改变协议的端口。 XML 次之,如果在 XML 中有配置,则 dubbo.properties 中的相应配置项无效。 Properties 最后&a…

【群智能算法改进】一种改进的蝴蝶优化算法 改进蝴蝶优化算法 改进BOA[1]【Matlab代码#35】

文章目录 【获取资源请见文章第5节:资源获取】1. 原始蝴蝶优化算法2. 改进蝴蝶优化算法2.1 动态转换概率策略2.2 最优邻域扰动策略2.3 随机惯性权重策略 3. 部分代码展示4. 仿真结果展示5. 资源获取6. 参考文献 【获取资源请见文章第5节:资源获取】 1. 原…