营销型网站建设思路,帝国CMS做的淘客网站,开发一个软件的步骤,wordpress相似的nodejs由于序列数据本质上是连续的#xff0c;因此我们在处理数据时需要解决这个问题。当序列过长而不能被模型一次性全部处理时#xff0c;我们希望能拆分这样的序列以便模型方便读取。
Q#xff1a;怎样随机生成一个具有n个时间步的mini batch的特征和标签#xff1f;
A…由于序列数据本质上是连续的因此我们在处理数据时需要解决这个问题。当序列过长而不能被模型一次性全部处理时我们希望能拆分这样的序列以便模型方便读取。
Q怎样随机生成一个具有n个时间步的mini batch的特征和标签
A从随机偏移量开始拆分序列以同时获得覆盖性和随机性。内容参考了李沐老师的动手学深度学习简化这个问题仅进行序列的切分不区分特征和标签二者逻辑基本一样
0 数据展示及问题 时间序列数据包含4个特征温度、湿度、降水、气压有60000条左右记录。
目标根据24h内温度预测下一个24h内的温度。
如果直接把这个dataframe丢到dataloader里会怎样呢。比如按照batch_size24进行划分使一组数据包含24个记录。
df pd.read_csv(../data/2013-2022-farm/farm.csv)
dataloader torch.utils.data.DataLoader(df.iloc[:, 1:].values, batch_size24, shuffleTrue)结果如下
for data in dataloader:print(data)print()可以看到这样处理后得到的序列实际上只有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_steps5为例可能产生的切割有 在程序中步长设为24执行前后data从60695变为60684 2、计算能够产生多少个子序列
num_subseqs (len(data) - 1) // num_steps结果 ( 60684 − 1 ) ÷ 24 2528 (60684 - 1) \div 24 2528 (60684−1)÷242528
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设置为32 # 总批量个数等于子序列个数 / 小批量大小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_stepsdatabatch_size32num_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迭代器产生数据而初始时的偏移量是随机的最终有机会获得所有可能的序列
随机偏移量切割情况 可能获得的序列如下每次完整运行seq_data_iter_random时可以产生下述示意图中的一行数据(但每一行中的子序列顺序随机)多次运行可以覆盖所有的情况。 2 顺序分区
保证两个相邻的小批量在原始序列中也是相邻的。保留了拆分的子序列的顺序因此称为顺序分区。
有一说一我感觉把上面那行shuffleTrue改一下不就好了嘛。
注意不是指在一个小批量里的数据是相邻的而是两个不同的小批量的相邻访问性质。
2.1 代码实现
def seq_data_iter_sequential(data, batch_size, num_steps, num_features1):# 从偏移量开始拆分序列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# 访问各个batchfor i in range(0, num_steps * num_batches, num_steps):X Xs[:, i:i num_steps]yield X1、随机偏移量
和上述流程比较类似不再解释 # 从偏移量开始拆分序列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)执行前后 可以理解为将一整个序列先拆分为32个小序列。然后每一个batch从32个小序列中取一个元素。
# 求得批量总数
num_batches Xs.shape[1] // num_steps
# 1896 // 24 793、访问各个batch
# 访问各个batch
for i in range(0, num_steps * num_batches, num_steps):X Xs[:, i:i num_steps]yield X2.2 说明
以batch_size 3, num_steps2为例首先将一整个序列折叠为3份。
然后每一个batch顺序地分别从3份中选择两个元素 3 封装为Dataloader
class SeqDataLoader:加载序列数据的迭代器def __init__(self, data, batch_size, num_steps, use_random_iter, num_features1):if use_random_iter:self.data_iter_fn self.seq_data_iter_randomelse:self.data_iter_fn self.seq_data_iter_sequentialself.data dataself.batch_size, self.num_steps batch_size, num_stepsself.num_features num_featuresdef seq_data_iter_random(self, data, batch_size, num_steps, num_features1):# 随机初始化位置对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_features1):# 从偏移量开始拆分序列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# 访问各个batchfor i in range(0, num_steps * num_batches, num_steps):X Xs[:, i:i num_steps]yield Xdef __iter__(self):return self.data_iter_fn(self.data, self.batch_size, self.num_steps, self.num_features)使用方法
dataloader SeqDataLoader(data, batch_size32, num_steps24, use_random_iterFalse, num_features4)
for X in dataloader:print(X)4 带有标签和归一化的DataLoader
根据num_steps的数据预测predict_steps的数据。 获取标签Y的逻辑与上类似下次填坑。 可使用.normalization函数进行归一化.reverse_normalization函数复原。
import random
import pandas as pd
import torch.utils.datafrom sklearn.preprocessing import MinMaxScaler# 将时间序列文件分为小批量
class SeqDataLoader:加载序列数据的迭代器根据num_steps的数据预测predict_steps的数据def __init__(self, data, batch_size, num_steps, use_random_iter, num_features1, predict_steps1):if use_random_iter:self.data_iter_fn self.seq_data_iter_randomelse:self.data_iter_fn self.seq_data_iter_sequentialself.data dataself.batch_size, self.num_steps, self.predict_steps batch_size, num_steps, predict_stepsself.num_features num_featuresself.scaler MinMaxScaler()self.normalization()def seq_data_iter_random(self, data, batch_size, num_steps, num_features1, predict_steps1):# 随机初始化位置对data进行切割得到新的data列表data data[random.randint(0, num_steps - 1):]# 减去predict_steps以保证子序列可获得对应的标签而不会越界num_subseqs (len(data) - self.predict_steps) // 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]Y [data[j num_steps: j num_steps predict_steps] for j in initial_indices_per_batch]yield torch.tensor(X), torch.tensor(Y)def seq_data_iter_sequential(self, data, batch_size, num_steps, num_features1, predict_steps1):# 从偏移量开始拆分序列offset random.randint(0, num_steps)# 计算偏移offset后的序列长度减去predict_steps以保证子序列可获得对应的标签而不会越界num_tokens ((len(data) - offset - predict_steps) // batch_size) * batch_size# 截取序列Xs torch.tensor(data[offset: offset num_tokens])# Ys从后一个时间序列开始截取表示labelYs torch.tensor(data[offset num_steps: offset num_tokens num_steps])# 变形为第一维度为batch_size大小Xs Xs.reshape(batch_size, -1, num_features)Ys Ys.reshape(batch_size, -1, num_features)# 求得批量总数num_batches Xs.shape[1] // num_steps# 访问各个batchfor i in range(0, num_steps * num_batches, num_steps):X Xs[:, i:i num_steps]Y Ys[:, i:i predict_steps]yield X, Ydef __iter__(self):return self.data_iter_fn(self.data, self.batch_size, self.num_steps, self.num_features, self.predict_steps)def normalization(self):self.data self.scaler.fit_transform(self.data) # 对选定的列进行归一化self.data self.data.astype(float32)def reverse_normalization(self):self.data self.scaler.inverse_transform(self.data) # 恢复各列数据