使用k折交叉验证进行时序模型选择


70

问题: 我想确定一点,使用带有时间序列的k折叠交叉验证是否简单明了,还是在使用它之前需要特别注意?

背景: 我正在建模一个6年的时间序列(使用半马尔可夫链),每5分钟有一个数据样本。为了比较多个模型,我使用了6倍交叉验证,即通过分离6年中的数据,所以我的训练集(用于计算参数)的长度为5年,而测试集的长度为1年。我没有考虑时间顺序,因此我的不同设置是:

  • fold 1:训练[1 2 3 4 5],测试[6]
  • 第二折:训练[1 2 3 4 6],测试[5]
  • 第三折:训练[1 2 3 5 6],测试[4]
  • 第四步:训练[1 2 4 5 6],测试[3]
  • 第五步:训练[1 3 4 5 6],测试[2]
  • 第六步:训练[2 3 4 5 6],测试[1]。

我提出的假设是,每年彼此独立。我该如何验证?有没有参考资料显示k倍交叉验证与时间序列的适用性。


看看这篇文章,我发现helful francescopochetti.com/...
Henok小号门格斯图

Answers:


69

时间序列(或其他固有排序的数据)可能对交叉验证有问题。如果某种模式出现在第3年并保持4-6年,那么您的模型就可以继续使用,即使它不是第1和第2年的一部分。

对于时间序列,有时更原则的方法是前向链接,其中您的过程将如下所示:

  • 折叠1:训练[1],测试[2]
  • fold 2:训练[1 2],测试[3]
  • 第三折:训练[1 2 3],测试[4]
  • 第四步:训练[1 2 3 4],测试[5]
  • 第五步:训练[1 2 3 4 5],测试[6]

这样可以更准确地建模您在预测时会看到的情况,您可以在此基础上对过去的数据进行建模,并对前瞻性数据进行预测。它还可以使您了解建模对数据大小的依赖性。


1
谢谢。我了解到,就像Zach所说的那样,这是规范的方法。我知道为什么。我遇到的问题是,事实上它会考虑数据大小的变化,因此我不会得到模型的“真实”泛化错误。但是混合的错误是:泛化和数据大小。您是否知道其他一些参考(M.Hyndman除外)处理时间序列中的交叉验证?不要误会我的意思,这不是不是我不相信您在说什么,海因曼先生在说什么,这完全是有道理的。我简单的喜欢有不同的视角对点上的问题
的Mickaël小号

恐怕我不知道这样的参考,但是如果有人认识一个参考,我很想看看。
肯·威廉姆斯

1
@Wayne,我的意思是,此解决方案在每次折叠中都使用越来越多的培训数据。在我的数据中,年份之间肯定存在差异,但没有明显的趋势或季节性。
的Mickaël小号

3
@Mickael:您可以使用第一折:训练[1 2]测试[3];两倍:训练[2 3]测试[4];折叠3:如果您担心每次折叠使用越来越多的数据,请训练[3 4]测试[5]等。我的猜测是,即使没有趋势,使用半MC技术也无法真正打乱多年。
韦恩

3
@MickaëlS:我发现了这篇文件sciencedirect.com/science/article/pii/S0020025511006773,并认为可能对此感兴趣。他们将这种“规范”方法与其他两种方法进行了比较-“阻断助推器”和“不依赖依赖”方法。
thebigdog

26

我用于交叉验证时间序列模型的方法是滚动交叉验证。从用于训练目的的一小部分数据开始,为以后的数据点进行预测,然后检查预测的数据点的准确性。然后,将相同的预测数据点作为下一个训练数据集的一部分,并对后续数据点进行预测。

为了使事情直观,下面是相同的图片:

在此处输入图片说明

等效的R代码为:

i <- 36    #### Starting with 3 years of monthly training data 
pred_ets <- c()
pred_arima <- c()
while(i <= nrow(dt)){
  ts <- ts(dt[1:i, "Amount"], start=c(2001, 12), frequency=12)

  pred_ets <- rbind(pred_ets, data.frame(forecast(ets(ts), 3)$mean[1:3]))
	  pred_arima <- rbind(pred_arima, data.frame(forecast(auto.arima(ts), 3)$mean[1:3]))

  i = i + 3
}
names(pred_arima) <- "arima"
names(pred_ets) <- "ets"

pred_ets <- ts(pred_ets$ets, start=c(2005, 01), frequency = 12)
	pred_arima <- ts(pred_arima$arima, start=c(2005, 01), frequency =12)

accuracy(pred_ets, ts_dt)
accuracy(pred_arima, ts_dt)

对于使用R进行逻辑回归的方法,有什么方法可以做到这一点?
hlyates

1
@hlyates,据我所知有可能,您只需要稍微修改一下上面的代码即可。包括pred_lr(通过逻辑回归进行的预测),并相应地更改列的名称。
贾汀·加尔

22

进行时间序列交叉验证的“规范”方法(至少 @Rob Hyndman所述)是“滚动”数据集。

即:

  • 折叠1:训练[1],测试[2]
  • fold 2:训练[1 2],测试[3]
  • 第三折:训练[1 2 3],测试[4]
  • 第四步:训练[1 2 3 4],测试[5]
  • 第五步:训练[1 2 3 4 5],测试[6]

基本上,您的训练集不应包含测试集之后出现的信息。


13

ARIMA(p,d,q)d>0d

为了使交叉验证可以用作模型选择工具,您需要训练和测试数据之间的近似独立性。时间序列数据的问题在于,相邻数据点通常高度相关,因此标准的交叉验证将失败。对此的补救措施是在测试样品的两侧都在测试样品和训练样品之间留出间隙。您还需要在测试样本之前留出空隙的原因是,当您在时间上向前或向后移动时,相关性是对称的(考虑相关性)。

hvvh

  • fold 1:训练[1 2 3 4 5h],测试[6]
  • fold 2:训练[1 2 3 4h h6],测试[5]
  • fold 3:训练[1 2 3h h5 6],测试[4]
  • 第四步:训练[1 2h h4 5 6],测试[3]
  • 第五次:训练[1h h3 4 5 6],测试[2]
  • 第六次:训练[h2 3 4 5 6],测试[1]

其中h表示训练样本的h观察在该侧被删除。


3

正如@thebigdog所评论的那样,“关于将交叉验证用于时间序列预测变量评估”,Bergmeir等人。讨论在固定时间序列的上下文中进行交叉验证,并确定正向链接(由其他答复者提出)无济于事。注意,前向链接在本文中称为“最后一个块评估”:

使用标准的5倍交叉验证,就最终误差是被低估还是被高估,都没有发现数据中依赖项的实际影响。相反,与交叉验证和块交叉验证相比,最后一个块评估往往会产生不那么鲁棒的错误度量。

Cerqueira等人的“ 评估时间序列预测模型:性能评估方法的实证研究 ”。同意这项评估。但是,对于非固定时间序列,他们建议改用Hold-Out的变体,称为Rep-Holdout。在Rep-Holdout中,a在时间序列中选择一个点Y以标记测试数据的开始。a确定该点在窗口内。如下图所示:

代表坚持图

前面提到的这篇文章篇幅冗长,并用公开的代码详尽地测试了该问题答案中提到的所有其他方法。这包括@Matthias Schmidtblaicher声称在测试数据之前和之后都包含差距。另外,我只是总结了这篇论文。本文的实际结论包括用于评估时间序列模型的决策树!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.