当前位置: 首页 > article >正文

时间序列模型在LSTM中的特征输入

这里写目录标题

  • 前言
  • LSTM的输入组成
    • 时间步
    • 例子
  • 实际代码解读
    • 特征提取
    • 处理成dataloader格式(用于输入到模型当中)
    • 对应到lstm的模型创建代码
  • 总结


前言

本文章将帮助理解如何将一个时间序列的各种特征(年月日的时间特征,滚动窗口滞后项等时变特征输入)输入到lstm模型(关键在于时间步)中,并给出使用pytorch进行特征输入的代码实例


LSTM的输入组成

包含三个部分

  • 样本数:输入样本数量
  • 时间步:一共使用多少个时间节点的数据进行预测(重点部分)
  • 特征数:某一个数据所具备的特征

时间步

时间步,具体指模型在一个样本中可以看到的时间序列数据的长度,即模型每次处理多少个连续的时间点
其实就是使用前(包括自己)n天的数据进行预测
由于时间步会使用前n天(类似于滞后的想法),所以使用n天时间步会导致样本缩小,所以实际输入(input_size)公式为
样本数量 − 时间步 + 1 样本数量 - 时间步 + 1 样本数量时间步+1 (要记得把自己算上哦)

时间步与滞后比较像,通过这样的对比帮助更好理解时间步:
滞后:取过去n期标志值作为当期特征
时间步:取算上自己的过去n期所有特征作为当期特征

例子

假设一个时间序列[1, 2, 3],在不考虑时间的情况下

  • 假设时间步为1,输入到lstm模型当中的_x应该为
    一个三维列表,其大小为
    (3, 1, 1),(样本数,时间步,特征值)

[
 [[1]],
 [[2]],
 [[3]]
]

  • 假设时间步为2,此时的输入大小则为(3, 2, 1)

[
 [[1], [2]],
 [[2], [3]]
]


实际代码解读

这里可以找gpt捏造一个数据,重点是理解过程中的数据处理
先简单对一个时间序列进行特征提取

特征提取

小贴士:LSTM对数据大小敏感,推荐优先进行

  • 归一化(数值大小关系)
  • 独热编码(没有大小和周期之分)
  • 正余弦编码(有周期不存在数值大小的特征)
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import torch
from tensorflow.python.keras.backend import dtype
from torch import nn, optim
from sklearn.preprocessing import MinMaxScaler
from torch.utils.data import DataLoader, TensorDataset

torch.random.manual_seed(42)
pd.set_option('display.max_columns', 500)
data = pd.read_csv('real_temp.csv')  
# 找gpt捏造的数据,其由两列组成,一列Date,一列Sales,时间范围为2023-01-01到2023-12-31
# 其中设置前十一个月用于训练,十二月用于测试
data["Date"] = pd.to_datetime(data["Date"])  # 转换为时间列
dt = data["Date"].dt  # 设置时间接口
data["month"] = dt.month  
data["day"] = dt.day
data["weekday"] = dt.weekday

def SinCosScale(name, round):
	"""正余弦化处理,公式为sin(2Π * 值 / 周期),cos(2Π * 值 / 周期)"""
    data[f"sin_{name}"] = np.sin(2 * np.pi * data[name] / round)  
    data[f"cos_{name}"] = np.cos(2 * np.pi * data[name] / round)
SinCosScale("weekday", 7)
SinCosScale("month", 12)

values = ["Sales", "day", "shift", "windowmean", "windowstd"]  # 将具有大小之分的数据进行归一化
# 为什么日期也包括在里面呢,因为不同月份对应的day其实不同,这里不太好处理
data["shift"] = data["Sales"].shift(7)  # 滞后特征
rolling = data["Sales"].rolling(7)  # 滚动窗口
data["windowmean"] = rolling.mean()  # 窗口内的均值
data["windowstd"] = rolling.std()  # 窗口内的标准差
scaler = MinMaxScaler()
scalar_test = MinMaxScaler()  # 用于专门转换y值的归一化模型
scalar_test.fit(data["Sales"].values.reshape(-1, 1))  # 输入y值进行训练,方便后续inverse
data[values] = scaler.fit_transform(data[values])
data.dropna(inplace=True)
data.drop(["month", "weekday"], inplace=True, axis=1)

处理成dataloader格式(用于输入到模型当中)

通过TensorDataloader转换为张量数据,通过TensorDataset能够让模型训练的部分模板化,强烈推荐使用

tran_mask =  (data["Date"] <= "2023-12-01")  # 训练集的范围
test_mask = (data["Date"] >= "2023-12-01") & (data["Date"] <= "2025-12-31")  # 测试集范围
train_data = data[tran_mask].values[:, 1:]  # 取出训练集(不包括Date)
test_data = data[test_mask].values[:, 1:]  # 取出测试集(不包括Date)
def create_sequences(data, time_steps):
    """取出时间步数据"""
    x, y = [], []  # 这里的x其实是所有带时间步的汇总
    for i in range(len(data) - time_steps):
        x.append(data[i:i + time_steps]) 
        # 选择从 i 开始的 time_steps 个时间步,这里已经是一个二维列表了,其中每一个元素都对应过去的一个时间节点的所有数据
        y.append(data[i + time_steps][0])    
        # 选择第 i + time_steps 个数据作为目标
    return np.array(x).astype("float32"), np.array(y).astype("float32").reshape(-1, 1)
train_x, train_y = create_sequences(train_data, 7)
test_x, test_y = create_sequences(test_data, 7)
train_inputs = TensorDataset(torch.tensor(train_x, dtype=torch.float32), torch.tensor(train_y, dtype=torch.float32))  # 转换为张量数据,通过TensorDataset能够让模型训练的部分完全模板化,强烈推荐使用
test_inputs = TensorDataset(torch.tensor(test_x, dtype=torch.float32), torch.tensor(test_y, dtype=torch.float32))
train_dataloader = DataLoader(dataset=train_inputs, batch_size=32, shuffle=True)
test_dataloader = DataLoader(dataset=test_inputs, batch_size=32)

对应到lstm的模型创建代码

注意lstm中的输入层,其大小应该为特征的数量
如果只设置了值为特征,那么input_size就为1
如果设置了8个特征,那么算上自己的值之后input_size就为9

class LSTM(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(LSTM, self).__init__()
        self.lstm = nn.LSTM(input_size, hidden_size, batch_first=True)  # lstm的返回有两个值,所以不能直接用sequential
        self.fc = nn.Linear(hidden_size, output_size)  # 线性

    def forward(self, x):
        # (样本大小, 时间步,特征数量)
        x, _ = self.lstm(x)  # x代表输出的形状,_是用于下一步处理,简单lstm就不用这个了
        x = x[:, -1, :]  # 只取最后一个时间步
        x = self.fc(x)  # 将输入的x转换为output_size尺寸
        return x
# 设置接口
input_size, hidden_size = 9, 8  # 输入的为特征数量
lstm = LSTM(input_size, hidden_size, 1)  # input_size为特征数量

其他代码这里就不放了,后面都是模板,问gpt,看其他文章都差不多,不浪费时间:

  • 设置优化器损失函数,数据移入device
  • for epoch 个训练,每个epoch中for data in dataloader:(这也是我觉得dataloader好的地方,也可以帮助我们将数据分批次与打乱,调整dataloader的batch_size即可)
  • 前向传播,计算损失,清空梯度,反向传播,更新参数
  • 测试集验证模型精度

总结

特征正常提取,和机器学习中的特征学习一样,假设n个特征
接下来对特征处理成时间步的形状,假设m个时间步,则每一个样本输入到模型中的大小
(1, m, n):一个样本算上自己的前m个时间节点,包含每个时间节点的n个特征


http://www.kler.cn/a/420959.html

相关文章:

  • centos 手动安装libcurl4-openssl-dev库
  • python源码实例游戏开发小程序办公自动化网络爬虫项目开发源码(250+个项目、26.6GB)
  • Meta-Llama-3-8B-Instruct 模型的混合精度训练显存需求:AdamW优化器(中英双语)
  • yarn install遇到问题处理
  • 【系统架构设计师】真题论文: 论软件质量保证及其应用(包括解题思路和素材)
  • ubuntu 和windows时区设置和时间修改
  • AlmaLinux8.10安装samba实现与Windows文件共享
  • 获取联通光猫的管理员密码
  • 【AI日记】24.12.03 kaggle 比赛 Titanic-6
  • SVN客户端及语言包免费下载 无需积分
  • 计算机网络八股整理(四)
  • 【SpringBoot】SpringBoot优雅停机机制
  • Springboot(五十)SpringBoot3集成sentinel并连接sentinel-dashboard
  • 【大数据学习 | 面经】Spark3.x对比2.x有哪些优点
  • 通过搭建安消一体化管理体系,高校实现应急中心数字化转型升级新动能
  • 树和二叉树(概念 结构)
  • 手机租赁系统开发全攻略 创新服务助力企业智能转型
  • 库存管理如何做到“先进先出”?
  • delphi 12 idhttpsever(S)+idhttp(C) 实现简单的JSON API服务
  • Navicat连接SQL Server
  • 初始Python篇(9)—— 函数
  • Creating Server TCP listening socket *:6379: bind: No error
  • Logistic Regression(逻辑回归)、Maximum Likelihood Estimatio(最大似然估计)
  • 经典图论之道路与航线
  • 【阿来来gis规划师工具箱说明书】b03要素信息写入字段
  • Scala的正则表达式