【LSTM】读取时间序列数据 | 时间序列数据的小批量划分方法

news2024/11/28 11:59:00

由于序列数据本质上是连续的,因此我们在处理数据时需要解决这个问题。当序列过长而不能被模型一次性全部处理时,我们希望能拆分这样的序列以便模型方便读取。

Q:怎样随机生成一个具有n个时间步的mini batch的特征和标签?

A:从随机偏移量开始拆分序列,以同时获得覆盖性和随机性。(内容参考了李沐老师的动手学深度学习,简化这个问题,仅进行序列的切分,不区分特征和标签,二者逻辑基本一样)

0 数据展示及问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RUJs8Qwo-1686137669642)(【LSTM】读取时间序列数据-时间序列数据的小批量划分方法/image-20230607152658840.png)]

时间序列数据包含4个特征:温度、湿度、降水、气压,有60000条左右记录。

目标:根据24h内温度,预测下一个24h内的温度。

如果直接把这个dataframe丢到dataloader里会怎样呢。比如按照batch_size=24进行划分,使一组数据包含24个记录。

df = pd.read_csv('../data/2013-2022-farm/farm.csv')
dataloader = torch.utils.data.DataLoader(df.iloc[:, 1:].values, batch_size=24, shuffle=True)

结果如下:

for data in dataloader:
    print(data)
    print()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gvRWmJam-1686137669643)(【LSTM】读取时间序列数据-时间序列数据的小批量划分方法/image-20230607153154154.png)]

可以看到,这样处理后,得到的序列实际上只有2529个,完全没有好好地利用整个序列。

而且data代表的其实不是一个小batch,而是一条序列数据。

1 随机抽样

1.1 实现

每个样本都是在原始的长序列上任意捕获的子序列。先给出整体代码,然后进行解释。

def seq_data_iter_random(data, batch_size, num_steps):
    # 随机初始化位置对data进行切割得到新的data列表
    data = data[random.randint(0, num_steps - 1):]
    # 能够得到的子序列数目
    num_subseqs = (len(data) - 1) // num_steps

    # 创建一个新的列表, 用于记录子序列的开始位置
    initial_indices = list(range(0, num_subseqs * num_steps, num_steps))

    # 随机打乱各个子序列的顺序
    random.shuffle(initial_indices)

    # 总批量个数等于:子序列个数 / 小批量大小
    num_batches = num_subseqs // batch_size

    # 每次取batch_size个数据
    for i in range(0, batch_size * num_batches, batch_size):
        # 取batch_size个数值,取出该批量的子序列的开始位置
        initial_indices_per_batch = initial_indices[i:i + batch_size]
        X = [data[j: j + num_steps] for j in initial_indices_per_batch]
        yield torch.tensor(X)

使用示例,本质上是一个迭代器:

df = pd.read_csv('../data/2013-2022-farm/farm.csv')
data = df.iloc[:, 1:].values
for X in seq_data_iter_random(data, 32, 24):
    print(X)

1、在步长内随机初始化位置对data进行切割

data = data[random.randint(0, num_steps - 1):]

因为不同的随机偏移量可以得到不同的子序列,这样能够提高覆盖性。

num_steps=5为例,可能产生的切割有:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7Xk3Ub3Q-1686137669643)(【LSTM】读取时间序列数据-时间序列数据的小批量划分方法/image-20230607161433381.png)]

在程序中,步长设为24,执行前后,data从60695变为60684:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KejYc1vz-1686137669643)(【LSTM】读取时间序列数据-时间序列数据的小批量划分方法/image-20230607161558890.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TJPSXUui-1686137669643)(【LSTM】读取时间序列数据-时间序列数据的小批量划分方法/image-20230607161836583.png)]

2、计算能够产生多少个子序列

num_subseqs = (len(data) - 1) // num_steps

结果: ( 60684 − 1 ) ÷ 24 = 2528 (60684 - 1) \div 24 = 2528 (606841)÷24=2528

3、创建一个新列表,用于得到子序列开始位置

	# 创建一个新的列表, 用于记录子序列的开始位置
    initial_indices = list(range(0, num_subseqs * num_steps, num_steps))
    # {list: 2528}[0, 24, 48, 72, 96, 120, 144, 168, 192, 216, ...]

    # 随机打乱各个子序列的顺序
    random.shuffle(initial_indices)

4、计算总批量大小

batch_size设置为24

	# 总批量个数等于:子序列个数 / 小批量大小
    num_batches = num_subseqs // batch_size
变量大小含义
data(60684, 4)
num_steps24步长
num_subseqs2528划分产生的子序列数目, d a t a n u m _ s t e p s \frac{data}{num\_steps} num_stepsdata
batch_size32
num_batches79能产生多少个批量,不足的一个批量的部分直接舍去, n u m _ s u b s e q s n u m _ b a t c h e s \frac{num\_subseqs}{num\_batches} num_batchesnum_subseqs

5、产生数据

    for i in range(0, batch_size * num_batches, batch_size):
        # 取batch_size个数值,取出该批量的子序列的开始位置
        initial_indices_per_batch = initial_indices[i:i + batch_size]
        X = [data[j: j + num_steps] for j in initial_indices_per_batch]
        yield torch.tensor(X)

循环进行num_batches

 # 每次取batch_size个数据,range (0, 2528, 32)
for i in range(0, batch_size * num_batches, batch_size):

循环体内,每次取batch_size个数值,取出该批量的子序列的开始位置:

initial_indices_per_batch = initial_indices[i:i + batch_size]
# {list: 32}[18456, 17232, 13320, 2904, 51240, 56472, 25056, 17040, 8040, 33936, 30792, 12312, 17328, 8304, 28128, 29976, 46560, 4680, 53928, 39096, 14616, 12240, 57120, 29784, 2784, 4752, 22272, 5040, 42600, 41856, 38232, 20448]

根据子序列的开始位置生成这个batch的子序列数据:

X = [data[j: j + num_steps] for j in initial_indices_per_batch]
yield torch.tensor(X)

1.2 说明

由于在训练过程中会不断地调用seq_data_iter_random迭代器产生数据,而初始时的偏移量是随机的,最终有机会获得所有可能的序列:

随机偏移量切割情况:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zPd85w91-1686137669644)(【LSTM】读取时间序列数据-时间序列数据的小批量划分方法/image-20230607164640835.png)]

可能获得的序列如下,每次完整运行seq_data_iter_random时,可以产生下述示意图中的一行数据(但每一行中的子序列顺序随机),多次运行可以覆盖所有的情况。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DUKNX0LK-1686137669644)(【LSTM】读取时间序列数据-时间序列数据的小批量划分方法/image-20230607164624333.png)]

2 顺序分区

保证两个相邻的小批量在原始序列中也是相邻的。保留了拆分的子序列的顺序,因此称为顺序分区。

有一说一我感觉把上面那行shuffle=True改一下不就好了嘛。

注意:不是指在一个小批量里的数据是相邻的,而是两个不同的小批量的相邻访问性质。

2.1 代码实现

def seq_data_iter_sequential(data, batch_size, num_steps, num_features=1):

    # 从偏移量开始拆分序列
    offset = random.randint(0, num_steps)
    # 计算偏移offset后的序列长度
    num_tokens = ((len(data) - offset - 1) // batch_size) * batch_size

    # 截取序列
    Xs = torch.tensor(data[offset: offset + num_tokens])

    # 变形为第一维度为batch_size大小;
    Xs = Xs.reshape(batch_size, -1, num_features)

    # 求得批量总数
    num_batches = Xs.shape[1] // num_steps

    # 访问各个batch
    for i in range(0, num_steps * num_batches, num_steps):
        X = Xs[:, i:i + num_steps]
        yield X

1、随机偏移量

和上述流程比较类似,不再解释

    # 从偏移量开始拆分序列
    offset = random.randint(0, num_steps)
    # 计算偏移offset后的序列长度
    num_tokens = ((len(data) - offset - 1) // batch_size) * batch_size
    # 截取序列
    Xs = torch.tensor(data[offset: offset + num_tokens])

2、第一维度修改为batch_size大小

Xs = data.reshape(batch_size, -1, num_features)

执行前后:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HcZDt8UW-1686137669644)(【LSTM】读取时间序列数据-时间序列数据的小批量划分方法/image-20230607175223595.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xQcUYEQR-1686137669644)(【LSTM】读取时间序列数据-时间序列数据的小批量划分方法/image-20230607175241903.png)]

可以理解为将一整个序列,先拆分为32个小序列。然后每一个batch从32个小序列中取一个元素。

# 求得批量总数
num_batches = Xs.shape[1] // num_steps
# 1896 // 24 = 79

3、访问各个batch

# 访问各个batch
for i in range(0, num_steps * num_batches, num_steps):
	X = Xs[:, i:i + num_steps]
    yield X

2.2 说明

batch_size = 3, num_steps=2为例,首先将一整个序列折叠为3份。

然后每一个batch顺序地分别从3份中选择两个元素

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9wXoVJHF-1686137669645)(【LSTM】读取时间序列数据-时间序列数据的小批量划分方法/image-20230607191032420.png)]

3 封装为Dataloader

class SeqDataLoader:

    """加载序列数据的迭代器"""
    def __init__(self, data, batch_size, num_steps, use_random_iter, num_features=1):
        if use_random_iter:
            self.data_iter_fn = self.seq_data_iter_random
        else:
            self.data_iter_fn = self.seq_data_iter_sequential

        self.data = data
        self.batch_size, self.num_steps = batch_size, num_steps
        self.num_features = num_features

    def seq_data_iter_random(self, data, batch_size, num_steps, num_features=1):
        # 随机初始化位置对data进行切割得到新的data列表
        data = data[random.randint(0, num_steps - 1):]
        num_subseqs = (len(data) - 1) // num_steps

        # 创建一个新的列表, 用于记录子序列的开始位置
        initial_indices = list(range(0, num_subseqs * num_steps, num_steps))

        # 随机打乱各个子序列的顺序
        random.shuffle(initial_indices)

        # 总批量个数等于:子序列个数 / 小批量大小
        num_batches = num_subseqs // batch_size

        # 每次取batch_size个数据
        for i in range(0, batch_size * num_batches, batch_size):
            # 取batch_size个数值,取出该批量的子序列的开始位置
            initial_indices_per_batch = initial_indices[i:i + batch_size]
            X = [data[j: j + num_steps] for j in initial_indices_per_batch]
            yield torch.tensor(X)

    def seq_data_iter_sequential(self, data, batch_size, num_steps, num_features=1):
        # 从偏移量开始拆分序列
        offset = random.randint(0, num_steps)
        # 计算偏移offset后的序列长度
        num_tokens = ((len(data) - offset - 1) // batch_size) * batch_size

        # 截取序列
        Xs = torch.tensor(data[offset: offset + num_tokens])

        # 变形为第一维度为batch_size大小;
        Xs = Xs.reshape(batch_size, -1, num_features)

        # 求得批量总数
        num_batches = Xs.shape[1] // num_steps

        # 访问各个batch
        for i in range(0, num_steps * num_batches, num_steps):
            X = Xs[:, i:i + num_steps]
            yield X

    def __iter__(self):
        return self.data_iter_fn(self.data, self.batch_size, self.num_steps, self.num_features)

使用方法:

dataloader = SeqDataLoader(data, batch_size=32, num_steps=24, use_random_iter=False, num_features=4)
for X in dataloader:
    print(X)

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

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

相关文章

4.2 Spark SQL数据源 - 基本操作

一、默认数据源 案例演示读取Parquet文件 查看Spark的样例数据文件users.parquet 1、在Spark Shell中演示 启动Spark Shell 查看数据帧内容 查看数据帧模式 对数据帧指定列进行查询,查询结果依然是数据帧,然后通过write成员的save()方法写入HDF…

还在为开发难度发愁?这个低代码平台能让你轻松搞定!

随着数字技术的不断发展,数字化也越来越深入人们的日常生活中,在这样的时代背景下,企业是需要通过不断创新来满足用户日益增长的业务需求。 使用背景 对企业而言,随着组织规模的扩大,各种业务流程系统需要持续而快速地…

浮点数的存储方式和取值范围

一、有符号整型的编码方式 1. 真值 把用""、"-"表示符号,数值部分用绝对值的编码的表示方式称为真值。 如3用4bit真值表示为0011,-1用真值表示为-0011。 2. 原码 符号位为0表示正数,符号位为1表示负数,数…

网络安全的究竟如何自学?

以十五派9年信息安全教育经验以及数千名学生摸索实践可以得知,在知乎上能够搜索到这个问题的人不外乎三种人: 第一种人在找网络安全入门的捷径; 第二种人想自己的方向进而获得认同感; 第三种人是已经在自学网络安全但是过程中碰…

卡尔曼滤波与组合导航原理(九)Sage-Husa自适应滤波

自适应滤波有很多种方式,也很实用 一、自适应滤波基本思想 函数模型 { X k Φ k / k − 1 X k − 1 Γ k − 1 W k − 1 Z k H k X k V k \left\{\begin{array}{l} \boldsymbol{X}_{k}\boldsymbol{\Phi}_{k / k-1} \boldsymbol{X}_{k-1}\boldsymbol{\Gamma}_{…

Mujoco xml编写(二)

目录 .1 运行 1.1 测试 .2 XML 2,1 基础 2.3 简单实例 2.3 进阶例子 .1 运行 1.1 测试 基于Mujoco210 Ubuntu 22.04配置安装_啥也不是的py人的博客-CSDN博客完成安装后 import mujoco_py import os mj_path mujoco_py.utils.discover_mujoco() xml_path os.path.join…

学习并深入理解闭包

前言 学习闭包前,先学点别的。 程序执行时: 1.编译阶段 创建变量对象GO,包括变量和函数作用域装在一块内存中。但是没有赋值,变量都是undefined,函数:0xxx 2.创建执行上下文 里面有VO对应ao(函数里的变量&#xff0…

数据结构 -- 跳跃链表

跳跃链表的概念 跳跃链表是有序链表的一个变种,在一个有序链表中,查找一个链表中的元素需要进行一次遍历,时间复杂度为O(n),为了加快查找的过程,能够跳过某些元素呢?一个思路就是牺牲一定的空间换时间&…

入职外包一个月,我离职了

有一种打工人的羡慕,叫做“大厂”。 真是年少不知大厂香,错把青春插稻秧。 但是,在深圳有一群比大厂员工更庞大的群体,他们顶着大厂的“名”,做着大厂的工作,还可以享受大厂的伙食,却没有大厂…

Redis系列第一篇:ubuntu18.04下源码编译安装Redis 6.2.12

Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。 Redis是一个key-value存储系统。和Memcached类似&#xff…

EasyExcel设置动态head数据(不是格式)及postman自测的坑

需求背景: 导出某某业务模块的数据,但是,数据列的标题内容是根据当前日期计算出来的。 比如今天是5月20,那么列就是 5/21 、 5/22…以此类推 问题: EasyExcel 通过Bean的注解实现匹配的,这是最便捷的方式&…

这5款小众又好用的软件,你都知道吗?

1.文件比较——WinMerge WinMerge是一款用于比较和合并文件和文件夹的工具。它可以让你对不同的文件和文件夹进行可视化的对比,并显示出差异和相似之处。WinMerge支持多种功能,如合并,同步,过滤,插件等。这款工具非常实用,但是可以提供强大的文件比较功能,是管理文件和解决冲突…

123 2021年国赛 二分搜索+前缀和

题目描述 小蓝发现了一个有趣的数列,这个数列的前几项如下: 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 小蓝发现,这个数列前 1 项是整数 1,接下来 2 项是整数 1 至 2,接下来 3 项是整数 1 至 3,接下来 4 项是整数…

day2 ARM处理器概论

目录 RISC处理器和CISC处理器 SOC(System on Chip) ARM指令集概述 指令集 ARM指令集 编译原理 ARM存储模型 ARM指令存储 ARM工作模式 工作模式的理解 ARM工作模式分类 RISC处理器和CISC处理器 RISC处理器 只保留常用的的简单指令,硬件结构简单,复…

你觉得你很优秀,为什么连一个软件测试面试都过不了?

目录 前言 简历请用数字化结果不要只是堆研工作经历 简历一:我的工作内容有 简历二:我的工作内容有: 当你和HR面对面坐下来时,迎接我们的第一个问题往往是:“来,请简单介绍下你自己吧。 了解你的过去是判断你未来的最好方式 增加好印象&#xff0c…

基于SVM的鸢尾花数据集回归分析

目录 1. 作者介绍2. SVM支持向量机算法2.1 鸢尾花数据集2.2 鸢尾花数据集可视化2.2.1 散点图2.2.2 箱型图2.2.3 三维散点图(3D) 3. SVM算法实现3.1 完整代码3.2 运行结果3.3 问题与分析 1. 作者介绍 张佳伦,男,西安工程大学电子信…

androidstudio ffmpeg 音频转换

java-ffmpeg-音频转换 需求描述功能流程所需条件步骤步骤1步骤2步骤3一些我使用中遇到的异常 需求描述 项目中的语音唤醒后的语音识别人声检测一直是一个很令我头痛的问题,之前因为对各种类型的工具包使用不熟练,以及时间问题,一直没有根治这个人声检测体验不好的问题,之前的解…

不同品牌或型号的单片机

以下是一些常见的单片机品牌和型号: 微控制器(Microchip):PIC系列(如PIC16F877A、PIC18F4550) 瑞萨电子(Renesas):RX系列(如RX231、RX65N)需要资…

Termius 最好用的SSH 连接工具

Termius 最好用的SSH 连接工具 一、环境准备二、配置2.1 terminus 安装2.2 删除自动更新2.3 修改用户信息 三、使用四、页面展示 该工具 mac os 可直接使用 本文只展示 windows 使用步骤,本教程使用的 termius 版本为 7.59.6 一、环境准备 termius 下载 官网下载地址…

ubuntu上安装docker报错

执行docker命令的时候报错如下: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? 为了解决这个问题,看了一些帖子有的说重启docker.service服务或者看该服务是否已经正常启动,结果网上…