LSTM二分类任务的多变量时间序列数据制备问题咨询
问题解答
1. 现有代码正确性校验
你的序列生成逻辑本身适配LSTM分类场景:用前sequence_length个时间步的特征预测最后一个时间步的类别,这个规则符合多变量时间序列分类的序列构建要求,最终生成的序列形状(样本数, 时间步, 特征数)也完全匹配LSTM模型的输入格式,这部分逻辑没有问题。
唯一需要修正的是代码小bug:generate_data函数参数传入的是X和y,但循环边界用的是len(data),这里依赖全局变量data,如果后续传入的X不是data的子集,会出现索引越界问题,建议改成len(X)。
你当前的训练测试集划分逻辑也符合时序要求:没有打乱样本顺序,完全按时间先后取前70%作为训练集、后30%作为测试集,不存在未来数据泄露的问题,这个实现是正确的。
2. 时序划分兼顾类别不平衡的方案
首先明确核心原则:时序场景下绝对不能为了类别平衡做随机分层抽样,否则会把未来时间段的数据混入训练集,导致数据泄露,模型上线后效果会严重失真。可以参考以下方案平衡需求:
- 第一步:优先在原始表格数据阶段做时序切分,再分别生成序列
你当前是先生成全量序列再按顺序切分,只要严格按顺序切分就不会有问题,但更稳妥的方式是先把未生成序列的原始表格数据按时间维度切分为训练原始集、测试原始集,再分别在两个数据集上独立生成序列,完全避免训练集用到测试集时间段的原始数据。 - 第二步:仅在训练集侧处理类别不平衡,测试集保留真实分布
测试集的类别分布要和真实线上分布一致,才能得到可信的评估结果,所以不要对测试集做任何采样操作,不平衡问题仅在训练阶段处理:- 方案1(优先推荐,不损失数据信息):训练时加入类别权重或使用不平衡损失函数
你的训练样本量超过800万,数据量充足,不需要改动原始训练数据分布,直接在模型训练时传入类别权重(比如Keras的class_weight参数、Pytorch的CrossEntropyLoss里的weight参数),或者使用Focal Loss,自动加大少数类样本的损失权重,既不会破坏时序结构,也不会损失数据信息。 - 方案2(数据量过小时选用):训练集侧做时序友好的采样
如果少数类样本量实在太少,可以对训练集做采样:多数类随机欠采样,或者用专门的时序过采样算法比如TimeSeriesSMOTE,不要用普通的SMOTE算法,会破坏序列的时序依赖关系。
- 方案1(优先推荐,不损失数据信息):训练时加入类别权重或使用不平衡损失函数
- 第三步:调整切分比例保证测试集少数类样本量
如果切分后测试集的少数类样本太少,无法支撑可靠的效果评估,可以适当调整切分比例(比如从7:3改成6:4),前提还是严格按时间顺序切分,不能打乱样本顺序。
3. 优化后代码示例
import numpy as np sequence_length = 10 def generate_data(X, y, sequence_length = 10, step = 1): X_local = [] y_local = [] # 修复原代码依赖全局变量的问题,改用传入的X计算长度 for start in range(0, len(X) - sequence_length, step): end = start + sequence_length X_local.append(X[start:end]) y_local.append(y[end-1]) return np.array(X_local), np.array(y_local) # 先切原始数据,再生成序列,避免数据泄露 raw_data_size = len(data) train_raw_size = int(raw_data_size * 0.7) # 原始数据按时间切分 train_raw_X = data.loc[:train_raw_size, "V1":"V4"].values train_raw_y = data.loc[:train_raw_size, "Class"].values test_raw_X = data.loc[train_raw_size:, "V1":"V4"].values test_raw_y = data.loc[train_raw_size:, "Class"].values # 独立生成训练和测试序列 X_train, y_train = generate_data(train_raw_X, train_raw_y, sequence_length) X_test, y_test = generate_data(test_raw_X, test_raw_y, sequence_length) # 校验类别分布 print("训练集类别统计:", np.unique(y_train, return_counts=True)) print("测试集类别统计:", np.unique(y_test, return_counts=True))
内容的提问来源于stack exchange,提问作者ForestGump
相关产品推荐
相关产品推荐

