多独立CSV数据集下LSTM时间序列预测的PyTorch实现疑问
问题描述
我正尝试训练一个LSTM模型,以5个特征作为网络输入来预测单个目标变量。我的数据集存储在多个独立CSV文件中,每个文件对应一个独立场景,时间范围从t=0s到t=100s,时间步长为1s,因此无法将它们按顺序堆叠。例如,若有50个CSV文件,每个文件包含100行(对应时间步)和6列(5个特征+1个目标变量),即每个文件是尺寸为(100*6)的二维矩阵。
我的目标是让LSTM接收长度为3的特征序列作为输入,逐次预测从t=0到t=100的未来单个目标值。我计划将50个数据集划分为训练集、验证集和测试集,现存在以下疑问:
- 如何高效地为训练集创建PyTorch Dataset和DataLoader?
- 为每个训练文件单独创建Dataset和DataLoader,逐个遍历所有训练文件,累加每个文件的损失后取平均值,这种方式是否合理?
- 由于所有数据都是时间序列数据(时间的函数),在使用DataLoader时是否应该设置shuffle=True?
我是机器学习初学者,具备相关基础。我曾尝试按问题2的方式创建Dataset和DataLoader,但未成功,希望获得相关技术反馈。
解答
1. 高效构建Dataset与DataLoader
推荐实现一个场景级的自定义Dataset,无需提前加载所有数据到内存,而是在取样本时动态读取单个CSV文件并生成序列。这种方式内存友好,且能统一管理所有训练样本。
自定义Dataset代码示例
import torch import pandas as pd from torch.utils.data import Dataset, DataLoader from glob import glob class SceneTimeSeriesDataset(Dataset): def __init__(self, csv_paths, seq_len=3): self.csv_paths = csv_paths self.seq_len = seq_len # 单个文件可生成的样本数:总时间步 - 序列长度 + 1 self.samples_per_file = 100 - seq_len + 1 def __len__(self): # 总样本数 = 文件数 × 单文件样本数 return len(self.csv_paths) * self.samples_per_file def __getitem__(self, idx): # 定位当前样本所属的文件和在文件内的位置 file_idx = idx // self.samples_per_file sample_pos = idx % self.samples_per_file # 读取CSV并拆分特征与目标 df = pd.read_csv(self.csv_paths[file_idx]) features = df.iloc[:, :5].astype(float).values # 前5列是特征 targets = df.iloc[:, 5].astype(float).values # 第6列是目标变量 # 生成输入序列(长度为3的特征序列) input_seq = torch.tensor(features[sample_pos : sample_pos+self.seq_len], dtype=torch.float32) # 生成对应目标:根据你的需求二选一 # 需求1:用[t, t+1, t+2]的特征预测t+2的目标值 target = torch.tensor(targets[sample_pos+self.seq_len-1], dtype=torch.float32) # 需求2:用[t, t+1, t+2]的特征预测t+3的目标值(注意要确保sample_pos+seq_len < 100) # target = torch.tensor(targets[sample_pos+self.seq_len], dtype=torch.float32) return input_seq, target
构建DataLoader
先划分训练/验证/测试的CSV路径:
# 获取所有CSV文件路径 all_csvs = glob("./your_data_dir/*.csv") # 按7:2:1划分训练/验证/测试集 train_csvs = all_csvs[:35] val_csvs = all_csvs[35:45] test_csvs = all_csvs[45:] # 创建Dataset和DataLoader train_dataset = SceneTimeSeriesDataset(train_csvs, seq_len=3) train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True) # shuffle的问题见下文 val_loader = DataLoader(SceneTimeSeriesDataset(val_csvs), batch_size=32, shuffle=False) test_loader = DataLoader(SceneTimeSeriesDataset(test_csvs), batch_size=32, shuffle=False)
2. 单文件单独创建Dataset的方式是否合理?
这种方式可行但不推荐,主要问题在于:
- 训练效率低:每个文件单独遍历,相当于频繁切换训练数据源,模型参数更新会过度受单个场景数据影响,容易导致泛化性差
- 手动累加损失易出错:比如忘记梯度清零、损失计算时混淆样本数与文件数,导致梯度更新异常
如果坚持用这种方式,需要注意:
- 每个文件训练前必须调用
optimizer.zero_grad()清零梯度 - 累加损失时要除以总训练样本数(不是文件数),确保损失均值计算正确
- 保持每个文件的批次大小一致,避免梯度波动过大
3. DataLoader是否需要shuffle=True?
- 训练集建议设shuffle=True:打乱不同场景的样本,让模型在混合场景的批次中训练,避免过度拟合单个场景的时间模式,提升泛化能力。注意这里的shuffle只是打乱样本的顺序,单个样本内部的时间序列(比如t0,t1,t2的特征)依然保持连续性,不会破坏时间逻辑。
- 验证/测试集必须设shuffle=False:评估模型时需要保持时间序列的连续性,模拟实际场景中从t=0到t=100的连续预测,这样得到的评估结果才真实有效。
内容的提问来源于stack exchange,提问作者CrocodileA
相关产品推荐
相关产品推荐

