R语言时间序列模型滚动窗口交叉验证实现正确性与工具问询
问题说明
我生成了如下时间序列数据:
library(forecast) library(lubridate) set.seed(123) weeks <- rep(seq(as.Date("2010-01-01"), as.Date("2023-01-01"), by = "week"), each = 1) counts <- rpois(length(weeks), lambda = 50) df <- data.frame(Week = as.character(weeks), Count = counts) # Convert Week column to Date format df$Week <- as.Date(df$Week) # Create a time series object ts_data <- ts(df$Count, frequency = 52, start = c(year(min(df$Week)), 1))
希望为该数据拟合时间序列模型,并实现滚动窗口交叉验证,验证逻辑为:
- 基于前60个数据点拟合模型,预测后续5个点并记录误差(RMSE、MAE、MAPE等)
- 基于前65个数据点拟合模型,预测后续5个点并记录误差
- 以此类推
我已尝试自行编写代码划分训练/测试块、实现模型训练测试及误差计算,还尝试了矩阵存储多步误差、子循环优化和结果绘图,现询问:
- 自己的实现是否正确?
- 是否有现成工具包可替代手动实现?
一、自定义实现的正确性检查
要确认你的代码对不对,盯着这几个核心点看就行:
- 不能有未来数据泄露:滚动窗口必须严格按时间顺序来,训练集的所有数据都得是测试集之前的,绝对不能让模型“看到”未来的数据。
- 窗口滑动逻辑匹配需求:你设定的是每次训练集加5个点、预测5个点,要确保每次滑动后,训练集的终点和测试集的起点是连续的,不能有间隔或者重叠。
- 误差计算没毛病:
- RMSE是预测值和真实值差的平方取均值再开方,别搞反顺序或者漏了开方
- MAE是绝对差的均值,这个相对简单
- MAPE要注意分母不能为0,你的计数数据都是非负的,但如果有真实值为0的情况得单独处理,不然会出问题
- 模型拟合逻辑统一:每次滚动拟合模型时,用的方法(比如
auto.arima())和参数要完全一样,不能这次用ARIMA,下次又换ETS,这样误差对比就没意义了。
如果你的代码都满足这些要求,那基本就是正确的。
二、现成工具包替代方案
不用自己写循环,R里有几个专门的工具包可以直接搞定:
1. forecast包的tsCV()函数
你已经在用forecast包了,它自带的tsCV()就是专门做时间序列交叉验证的,直接指定初始训练集大小和预测步长就行:
# 先定义一个预测函数,比如用auto.arima拟合模型再预测 forecast_func <- function(y, h) { forecast(auto.arima(y), h = h) } # 执行滚动验证:initial=60是初始训练集大小,h=5是每次预测的步数 cv_results <- tsCV(ts_data, forecast_func, h = 5, initial = 60) # 计算每一步预测的RMSE和MAE rmse_per_step <- colMeans(sqrt(cv_results^2), na.rm = TRUE) mae_per_step <- colMeans(abs(cv_results), na.rm = TRUE)
tsCV()会自动按时间顺序滚动窗口,返回的是预测误差矩阵,每行对应一个训练窗口,每列对应一步预测的误差,后续直接统计就行。
2. fable包(tidyverse风格时序工具)
fable是forecast的继任者,配合tsibble用起来更清爽,代码逻辑更直观:
library(fable) library(tsibble) # 把数据转换成tsibble格式(专门的时序数据框) tsibble_data <- df %>% as_tsibble(index = Week) # 定义滚动窗口规则:初始60个数据,每次滑动5个 rolling_plan <- tsibble_data %>% stretch_tsibble(initial = 60, step = 5) # 一键完成模型拟合、预测和误差计算 cv_results <- rolling_plan %>% model(ARIMA(Count)) %>% forecast(h = 5) %>% accuracy(tsibble_data) # 直接查看误差结果 print(cv_results)
这个方案输出的是整洁的数据框,后续做可视化或者统计都很方便。
3. caret包(适合机器学习模型的时序验证)
如果你想用机器学习模型做时序预测,caret可以自定义时间序列的重采样方案:
library(caret) # 创建时间序列切片:初始窗口60,预测步长5 time_slices <- createTimeSlices(1:length(ts_data), initialWindow = 60, horizon = 5, fixedWindow = FALSE) # 设置训练控制参数 train_control <- trainControl(method = "timeslice", index = time_slices$trainIndex, indexOut = time_slices$testIndex) # 训练模型(以ARIMA为例,也可以换其他机器学习模型) model <- train(x = data.frame(idx = 1:length(ts_data)), y = ts_data, method = "arima", trControl = train_control) # 查看模型的误差结果 print(model$results)
不过caret对纯时序模型的支持不如前面两个工具包灵活,更适合传统机器学习模型的时序验证场景。
内容的提问来源于stack exchange,提问作者stats_noob
相关产品推荐
相关产品推荐

