训练/验证/测试集流程正确性确认及交叉验证融入方法问询
训练/验证/测试集流程验证与时间序列交叉验证方案
一、你的流程理解修正
你的整体流程逻辑是对的,但有两个关键细节需要调整,避免影响模型泛化性:
- 拆分规则:时间序列数据必须严格按时间先后顺序划分训练/验证/测试集,绝对不能随机拆分(否则会出现「未来数据泄露」,让模型提前看到本应未知的信息)。比如按时间排序后,前70%为训练集,中间10%为验证集,最后20%为测试集。
- 最优模型的最终训练:当你用验证集调好超参数后,不能直接用之前仅在训练集上训练的模型预测测试集。正确做法是把训练集+验证集合并作为完整训练数据,用最优超参数重新训练模型,再用这个模型预测测试集——这样模型能利用更多数据,性能更稳定。
对应你的ARIMA代码,步骤6应该调整为:
# 合并训练集和验证集 full_train_set = pd.concat([training_set, validation_set]) # 用最优超参数重新训练 final_arima_model = ARIMA(endog=full_train_set, order=(best_p, best_d, best_q)).fit() # 预测测试集 test_forecast = final_arima_model.forecast(steps=len(test_set)) print('测试集MSE:', mean_squared_error(test_set, test_forecast))
二、时间序列场景的交叉验证实现
传统K折交叉验证(随机拆分)不适用于时间序列,必须用滚动时间窗口交叉验证——核心是每次用过去的时序数据训练,用紧接着的未来数据验证,逐步滚动窗口,避免数据泄露。
结合sklearn和ARIMA的具体步骤:
1. 先拆分出独立测试集
先从原始数据中按时间顺序拆分出20%作为最终测试集(全程只用来评估最终模型,不参与任何调参),剩下80%作为「训练+验证候选集」用于交叉验证。
2. 初始化时间序列拆分器
用sklearn的TimeSeriesSplit生成按时间顺序划分的fold:
from sklearn.model_selection import TimeSeriesSplit # 设置折数,比如5折 tscv = TimeSeriesSplit(n_splits=5)
它会自动生成如下fold:
- Fold1:训练集=前20%候选数据,验证集=接下来的16%
- Fold2:训练集=前36%候选数据,验证集=接下来的16%
- ...以此类推,逐步滚动窗口
3. 遍历超参数,用交叉验证选最优
定义ARIMA的超参数候选范围(比如order=(p,d,q)的组合),然后在每个fold上训练、评估,取平均MSE最小的参数:
import numpy as np from statsmodels.tsa.arima.model import ARIMA from sklearn.metrics import mean_squared_error # 超参数候选列表 param_candidates = [(1,1,0), (1,1,1), (2,1,0), (2,1,1), (0,1,1)] best_mse = float('inf') best_params = None for order in param_candidates: fold_mses = [] # 遍历每个时间窗口fold for train_idx, val_idx in tscv.split(train_val_candidate): train_fold = train_val_candidate[train_idx] val_fold = train_val_candidate[val_idx] # 训练ARIMA模型 model = ARIMA(endog=train_fold, order=order) fitted_model = model.fit() # 预测验证fold val_forecast = fitted_model.forecast(steps=len(val_fold)) # 计算MSE mse = mean_squared_error(val_fold, val_forecast) fold_mses.append(mse) # 计算当前参数的平均MSE avg_mse = np.mean(fold_mses) # 更新最优参数 if avg_mse < best_mse: best_mse = avg_mse best_params = order
4. 训练最终模型并评估测试集
用最优参数在全部训练+验证候选集上训练模型,最后用测试集评估泛化性能:
# 用最优参数训练完整模型 final_model = ARIMA(endog=train_val_candidate, order=best_params) final_fitted_model = final_model.fit() # 预测测试集并评估 test_forecast = final_fitted_model.forecast(steps=len(test_set)) print('测试集最终MSE:', mean_squared_error(test_set, test_forecast))
这种方式能更可靠地评估超参数的泛化能力,避免单一验证集带来的偶然性,同时严格遵循时间序列的时序逻辑,不会出现数据泄露。
内容的提问来源于stack exchange,提问作者mbih
相关产品推荐
相关产品推荐

