交叉验证季节性线性模型

时间:2012-12-26 18:28:54

标签: r regression forecasting cross-validation

我试图在我的线性模型上执行CV,该模型具有季节性虚拟变量,因此我无法随机抽样。

y = rnorm(120,0,3) + 20*sin(2*pi*(1:120)/12) 
x = months(ISOdate(2012,1:12,1))
reg.data = data.frame(y, x)
model = lm(y ~ x, data = reg.data)

我的简历功能是:

cross.valid = function(model, min.fit = as.integer(nrow(model$model)*0.7), h = 1)
{
  dados = model$model
  n.rows = nrow(dados)

  results = data.frame(pred = numeric(), actual = numeric())

  for (i in seq(1, n.rows - min.fit - h + 1, by = h))
  {
   dados.train = dados[1:(i + min.fit - 1), ]
   model <- update(model, data = dados.train)

   dados.pred = dados[(i + min.fit):(i + min.fit + h - 1), -1, drop = FALSE]

   predic = predict(model, newdata = dados.pred, interval = 'prediction')
   actual = dados[(i + min.fit):(i + min.fit + h - 1), 1]
   results = rbind(results, data.frame(pred = predic[1:h, 'fit'], actual = actual))
  }

  results
}

示例:

cv1 = cross.valid(model, h = 1)
mae = with(cv1, mean(abs(actual - pred )))
print(mae)

不同视野( h )的MAE值太接近了。代码本身有效吗?这样做有更好的解决方案/包吗?

谢谢!

1 个答案:

答案 0 :(得分:3)

我认为你的功能没有任何不正确之处。调查forecast包;我怀疑它会提供你需要的许多功能。

我简明扼要地重写了你的功能:

set.seed(1)
y = rnorm(120,0,3) + 20*sin(2*pi*(1:120)/12) 
x = months(ISOdate(2012,1:12,1))
reg.data = data.frame(y, x)

pred.set<-function(i,h) {
  train<-reg.data[1:(i + min.fit - 1),]
  test<-reg.data[(i + min.fit):(i + min.fit + h - 1),]
  pred<-predict(lm(y~x, data=train), newdata=test)
  abs(test$y - pred)
}

pred.by.horiz<-function(h) 
               mean(sapply(seq(1, nrows - min.fit - h + 1, by = h),pred.set,h=h))

pred.by.horiz完全匹配函数的输出(和后处理)。

正如您所提到的,地平线似乎不会影响MAE:

mae.by.h<-sapply(seq(nrows-min.fit),pred.by.horiz)
plot(mae.by.h,type='l',col='red',lwd=2,xlab='Horizon',ylab='Mean absolute error')

MAE by horizon

也许您预计随着预测范围的增加,平均误差会增加。对于许多时间序列模型,情况确实如此,但在几个月的线性模型中添加更多数据并不能帮助您预测系列中的下一个点(除非您添加12个月或更长时间)。

例如,考虑h为1时会发生什么。首先是84个月的数据,每个月7个数据点。现在,您将添加一个数据点,即下一月的数据,并尝试预测二月的结果。但是,您的额外数据点只会帮助您预测下一个 January ,这就是您的线性函数的工作方式。查看模型摘要:

lm(y ~ x, data = reg.data)
Coefficients:
(Intercept)      xAugust    xDecember    xFebruary     xJanuary  
   17.11380    -32.74962    -17.81076     -0.03235     -6.63998  
      xJuly        xJune       xMarch         xMay    xNovember  
  -26.69203    -17.41170      2.96735     -7.11166    -25.43532  
   xOctober   xSeptember  
  -33.56517    -36.93474 

每个预测都是基于两个变量,截距和预测月份。所以预测前面的一点并不比预测前五点更容易。这就是为什么随着地平线的增加MAE没有上升,问题在于你建模数据的方式,而不是MAE功能。

我对你的函数没有完全理解的一件事是你决定在每次迭代时增加h列的大小。看一下当你尝试增加1时会发生什么是显而易见的:

# Code to increment by 1
pred.by.horiz2<-
  function(h) mean(sapply(seq(1, nrows - min.fit - h + 1, by = 1),pred.set,h=h))
mae.by.h2<-sapply(seq(nrows-min.fit),pred.by.horiz2)
plot(mae.by.h2,type='l',col='red',lwd=2,xlab='Horizon',ylab='Mean absolute error')

MAE by horizon when incrementing h by 1

这里的模式很复杂,但是你会注意到,当地平线足够大以至于可以使用下一个点时,MAE开始减少到12点。

相关问题