交叉验证时间序列分析

机器算法验证 r 时间序列 交叉验证
2022-01-30 15:43:25

我一直在使用 R 中的caret 包来构建分类和回归的预测模型。Caret 提供了一个统一的接口来通过交叉验证或引导来调整模型超参数。例如,如果您正在构建一个简单的“最近邻居”模型进行分类,您应该使用多少个邻居?2?10?100?Caret 通过重新采样数据、尝试不同的参数,然后汇总结果来决定哪个产生最佳预测准确性,从而帮助您回答这个问题。

我喜欢这种方法,因为它为选择模型超参数提供了一种强大的方法,并且一旦您选择了最终的超参数,它使用分类模型的准确性提供了对模型“好”程度的交叉验证估计和 RMSE 用于回归模型。

我现在有一些时间序列数据,我想为其构建回归模型,可能使用随机森林。考虑到数据的性质,什么是评估模型预测准确性的好技术?如果随机森林并不真正适用于时间序列数据,那么为时间序列分析构建准确的集成模型的最佳方法是什么?

4个回答

“经典”k 次交叉验证技术基于这样一个事实,即可用数据集中的每个样本都使用 (k-1) 次来训练模型并使用 1 次来测试它。由于在“未来”数据上验证时间序列模型非常重要,因此这种方法不会有助于模型的稳定性。

许多(大多数?)时间序列的一个重要属性是相邻值之间的相关性。正如 IrishStat 所指出的,如果您使用以前的读数作为候选模型的自变量,则这种相关性(或缺乏独立性)起着重要作用,这也是 k 次交叉验证不是一个好主意的另一个原因。

克服这个问题的一种方法是对数据进行“过度采样”并对其进行去相关。如果去相关过程成功,那么在时间序列上使用交叉验证就会变得不那么成问题。但是,它不会解决使用未来数据验证模型的问题

澄清

通过在未来数据上验证模型,我的意思是构建模型,等待在模型构建、测试、微调等过程中不可用的新数据,并在数据上验证它。

通过对数据进行过采样,我的意思是以远高于实际需要的频率收集时间序列数据。例如:每 5 秒采样一次股票价格,此时您对每小时的变动非常感兴趣。在这里,当我说“采样”时,我并不是指“插值”、“估计”等。如果无法以更高的频率测量数据,那么这种技术就毫无意义

http://robjhyndman.com/researchtips/crossvalidation/包含时间序列交叉验证的快速提示。关于对时间序列数据使用随机森林......虽然这似乎是一个奇怪的选择,因为该模型是使用引导样本拟合的。当然,可以使用经典的时间序列方法(例如 ARIMA),神经网络等 ML 技术也可以使用(示例 pdf)。也许一些时间序列专家可以评论 ML 技术与时间序列特定算法相比的工作情况。

这是一些用于交叉验证时间序列模型的示例代码。在我的博客中扩展了这段代码,合并了foreach 包以加快速度,并允许在交叉验证中使用可能的 xreg 项。

这是来自 Rob Hyndman 博客的代码副本:

library(fpp) # To load the data set a10
plot(a10, ylab="$ million", xlab="Year", main="Antidiabetic drug sales")
plot(log(a10), ylab="", xlab="Year", main="Log Antidiabetic drug sales")

k <- 60 # minimum data length for fitting a model
n <- length(a10)
mae1 <- mae2 <- mae3 <- matrix(NA,n-k,12)
st <- tsp(a10)[1]+(k-2)/12

for(i in 1:(n-k))
{
  xshort <- window(a10, end=st + i/12)
  xnext <- window(a10, start=st + (i+1)/12, end=st + (i+12)/12)
  fit1 <- tslm(xshort ~ trend + season, lambda=0)
  fcast1 <- forecast(fit1, h=12)
  fit2 <- Arima(xshort, order=c(3,0,1), seasonal=list(order=c(0,1,1), period=12), 
      include.drift=TRUE, lambda=0, method="ML")
  fcast2 <- forecast(fit2, h=12)
  fit3 <- ets(xshort,model="MMM",damped=TRUE)
  fcast3 <- forecast(fit3, h=12)
  mae1[i,1:length(xnext)] <- abs(fcast1[['mean']]-xnext)
  mae2[i,1:length(xnext)] <- abs(fcast2[['mean']]-xnext)
  mae3[i,1:length(xnext)] <- abs(fcast3[['mean']]-xnext)
}

plot(1:12, colMeans(mae1,na.rm=TRUE), type="l", col=2, xlab="horizon", ylab="MAE",
     ylim=c(0.65,1.05))
lines(1:12, colMeans(mae2,na.rm=TRUE), type="l",col=3)
lines(1:12, colMeans(mae3,na.rm=TRUE), type="l",col=4)
legend("topleft",legend=c("LM","ARIMA","ETS"),col=2:4,lty=1)

结果

如果您有时间序列数据,那么您可能会遇到“自由度问题”。例如,如果您每隔一小时进行 4 次观察,然后决定以 1 分钟的间隔使用 241 次观察,则您有 241 次观察,但它们不一定是独立的。当您将这 241 个值/测量值提交到分析包时,该包可能会认为这些是 241 个独立值,因为它会继续执行它的特殊魔法。如果您有时间序列数据,您可能需要升级您的分析。我不知道您所指的程序,但我有一个合理的猜测(我可能错了!)它的测试(F 测试/T 测试...等)可能不适用于您的问题集。