使用R的时间序列分析过程和方法


13

我正在做一个小项目,我们试图预测未来6个月内商品(油,铝,锡等)的价格。我有12个这样的变量可以预测,并且我有2008年4月至2013年5月的数据。

我应该如何进行预测?我已经完成以下工作:

  • 导入的数据作为时间序列数据集
  • 所有变量的季节性都倾向于随趋势而变化,因此我将使用乘法模型。
  • 我将变量的对数转换为加性模型
  • 对于每个变量,使用STL分解数据

我打算使用Holt Winters指数平滑,ARIMA和神经网络进行预测。我将数据分为训练和测试(80、20)。计划选择MAE,MPE,MAPE和MASE较少的模型。

我做对了吗?

我还有一个问题是,在传递给ARIMA或神经网络之前,我应该对数据进行平滑处理吗?如果是,使用什么?数据显示季节性和趋势。

编辑:

附加时间序列图和数据 在此处输入图片说明

Year  <- c(2008, 2008, 2008, 2008, 2008, 2008, 2008, 2008, 2008, 2009, 2009, 
           2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2010, 
           2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 
           2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 
           2011, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 
           2012, 2012, 2013, 2013)
Month <- c(4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 
           12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 
           8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2) 
Coil  <- c(44000, 44500, 42000, 45000, 42500, 41000, 39000, 35000, 34000, 
           29700, 29700, 29000, 30000, 30000, 31000, 31000, 33500, 33500, 
           33000, 31500, 34000, 35000, 35000, 36000, 38500, 38500, 35500, 
           33500, 34500, 36000, 35500, 34500, 35500, 38500, 44500, 40700, 
           40500, 39100, 39100, 39100, 38600, 39500, 39500, 38500, 39500, 
           40000, 40000, 40500, 41000, 41000, 41000, 40500, 40000, 39300, 
           39300, 39300, 39300, 39300, 39800)
coil <- data.frame(Year = Year, Month = Month, Coil = Coil)

编辑2: 一个问题,能否请您告诉我我的数据是否具有季节性或趋势?另外,请给我一些有关如何识别它们的提示。 在此处输入图片说明 在此处输入图片说明


2
如果您正在尝试预测商品组,例如各种类型的金属(钢A,钢B,钢C等),那么可能值得测试协整的存在。例如,这样的话:钢铁价格会一起波动吗?。与单变量方法相比,这可能会提供更好的6个月(中长期)预测,但这确实是您要尝试的困难游戏。;-)
Graeme Walsh

1
正如@GraemeWalsh指出的那样,单变量趋势外推法可能不适用于此类数据。文献中有完善的预测石油,钢铁价格的方法可能值得探讨。
天气预报员

1
您可以将新编辑作为一个单独的问题发布吗?由于您已经接受了答案,因此新问题可能无法引起它的注意。通过观察数据,我可以说它们没有趋势或季节性模式。正如我在下面的帖子中所指出的,2009年之前的下降趋势看起来像是经济衰退之类的宏观经济现象?
天气预报员

@ forecaster,@ GraemeWalsh:谢谢。我打算通过ADF测试使用协整方法。
Niranjan Sonachalam'3

1
您已在新问题中提供了上下文,这现在很容易理解。因此,2009年之前的跌幅确实是一些宏观经济现象。在这种情况下,请使用具有漂移或(arima(0,1,0)+ drift
预报者

Answers:


21

您应该使用Forecast软件包,该软件包支持所有这些模型(以及更多模型),并使其易于安装:

library(forecast)
x <- AirPassengers
mod_arima <- auto.arima(x, ic='aicc', stepwise=FALSE)
mod_exponential <- ets(x, ic='aicc', restrict=FALSE)
mod_neural <- nnetar(x, p=12, size=25)
mod_tbats <- tbats(x, ic='aicc', seasonal.periods=12)
par(mfrow=c(4, 1))
plot(forecast(mod_arima, 12), include=36)
plot(forecast(mod_exponential, 12), include=36)
plot(forecast(mod_neural, 12), include=36)
plot(forecast(mod_tbats, 12), include=36)

我建议不要在拟合模型之前对数据进行平滑处理。您的模型本质上将尝试平滑数据,因此预平滑只会使事情复杂化。

在此处输入图片说明

根据新数据进行编辑:

实际上,有形Arima是您可以为此培训和测试集选择的最差的模型之一。

我将您的数据保存到文件调用中coil.csv,将其加载到R中,然后将其拆分为训练和测试集:

library(forecast)
dat <- read.csv('~/coil.csv')
x <- ts(dat$Coil, start=c(dat$Year[1], dat$Month[1]), frequency=12)
test_x <- window(x, start=c(2012, 3))
x <- window(x, end=c(2012, 2))

接下来,我拟合一系列时间序列模型:Arima,指数平滑,神经网络,tbat,bats,季节性分解和结构时间序列:

models <- list(
  mod_arima = auto.arima(x, ic='aicc', stepwise=FALSE),
  mod_exp = ets(x, ic='aicc', restrict=FALSE),
  mod_neural = nnetar(x, p=12, size=25),
  mod_tbats = tbats(x, ic='aicc', seasonal.periods=12),
  mod_bats = bats(x, ic='aicc', seasonal.periods=12),
  mod_stl = stlm(x, s.window=12, ic='aicc', robust=TRUE, method='ets'),
  mod_sts = StructTS(x)
  )

然后,我做了一些预测,并与测试集进行了比较。我包含了一个幼稚的预测,它总是预测一条平坦的水平线:

forecasts <- lapply(models, forecast, 12)
forecasts$naive <- naive(x, 12)
par(mfrow=c(4, 2))
for(f in forecasts){
  plot(f)
  lines(test_x, col='red')
}

在此处输入图片说明

如您所见,Arima模型误解了趋势,但我有点像“基本结构模型”的外观

最后,我在测试集上测量了每个模型的准确性:

acc <- lapply(forecasts, function(f){
  accuracy(f, test_x)[2,,drop=FALSE]
})
acc <- Reduce(rbind, acc)
row.names(acc) <- names(forecasts)
acc <- acc[order(acc[,'MASE']),]
round(acc, 2)
                ME    RMSE     MAE   MPE MAPE MASE ACF1 Theil's U
mod_sts     283.15  609.04  514.46  0.69 1.27 0.10 0.77      1.65
mod_bats     65.36  706.93  638.31  0.13 1.59 0.12 0.85      1.96
mod_tbats    65.22  706.92  638.32  0.13 1.59 0.12 0.85      1.96
mod_exp      25.00  706.52  641.67  0.03 1.60 0.12 0.85      1.96
naive        25.00  706.52  641.67  0.03 1.60 0.12 0.85      1.96
mod_neural   81.14  853.86  754.61  0.18 1.89 0.14 0.14      2.39
mod_arima   766.51  904.06  766.51  1.90 1.90 0.14 0.73      2.48
mod_stl    -208.74 1166.84 1005.81 -0.52 2.50 0.19 0.32      3.02

Hyndman,RJ和Athanasopoulos,G.(2014)“预测:原则与实践”中描述了所使用的度量标准,这些人也恰好是预测软件包的作者。我强烈建议您阅读他们的文字:该文字可免费在线获得。结构时间序列是包括MASE在内的多个指标的最佳模型,MASE是我倾向于选择模型的指标。

最后一个问题是:结构模型在此测试集上是否很幸运?评估这种情况的一种方法是查看训练集错误。训练集错误不如测试集错误可靠(因为它们可能过度拟合),但是在这种情况下,结构模型仍然是最重要的:

acc <- lapply(forecasts, function(f){
  accuracy(f, test_x)[1,,drop=FALSE]
})
acc <- Reduce(rbind, acc)
row.names(acc) <- names(forecasts)
acc <- acc[order(acc[,'MASE']),]
round(acc, 2)
                ME    RMSE     MAE   MPE MAPE MASE  ACF1 Theil's U
mod_sts      -0.03    0.99    0.71  0.00 0.00 0.00  0.08        NA
mod_neural    3.00 1145.91  839.15 -0.09 2.25 0.16  0.00        NA
mod_exp     -82.74 1915.75 1359.87 -0.33 3.68 0.25  0.06        NA
naive       -86.96 1936.38 1386.96 -0.34 3.75 0.26  0.06        NA
mod_arima  -180.32 1889.56 1393.94 -0.74 3.79 0.26  0.09        NA
mod_stl     -38.12 2158.25 1471.63 -0.22 4.00 0.28 -0.09        NA
mod_bats     57.07 2184.16 1525.28  0.00 4.07 0.29 -0.03        NA
mod_tbats    62.30 2203.54 1531.48  0.01 4.08 0.29 -0.03        NA

(请注意,神经网络过拟合,在训练集上表现出色,而在测试集上表现不佳)

最后,最好对所有这些模型进行交叉验证,也许是通过在2008-2009年/ 2010年测试,2008-2010年/ 2011年测试,2008-2011年/ 2012年测试,培训在2008-2012年/在2013年进行测试,并在所有这些时间段内平均误差。如果您想走这条路,我有一个部分完整的软件包,可以在github上交叉验证时间序列模型,我很乐意您尝试一下并给我以下方面的反馈/拉取请求:

devtools::install_github('zachmayer/cv.ts')
library(cv.ts)

编辑2:让我们看看我是否还记得如何使用自己的软件包!

首先,从github安装和加载该软件包(请参见上文)。然后交叉验证一些模型(使用完整的数据集):

library(cv.ts)
x <- ts(dat$Coil, start=c(dat$Year[1], dat$Month[1]), frequency=12)
ctrl <- tseriesControl(stepSize=1, maxHorizon=12, minObs=36, fixedWindow=TRUE)
models <- list()

models$arima = cv.ts(
  x, auto.arimaForecast, tsControl=ctrl,
  ic='aicc', stepwise=FALSE)

models$exp = cv.ts(
  x, etsForecast, tsControl=ctrl,
  ic='aicc', restrict=FALSE)

models$neural = cv.ts(
  x, nnetarForecast, tsControl=ctrl,
  nn_p=6, size=5)

models$tbats = cv.ts(
  x, tbatsForecast, tsControl=ctrl,
  seasonal.periods=12)

models$bats = cv.ts(
  x, batsForecast, tsControl=ctrl,
  seasonal.periods=12)

models$stl = cv.ts(
  x, stl.Forecast, tsControl=ctrl,
  s.window=12, ic='aicc', robust=TRUE, method='ets')

models$sts = cv.ts(x, stsForecast, tsControl=ctrl)

models$naive = cv.ts(x, naiveForecast, tsControl=ctrl)

models$theta = cv.ts(x, thetaForecast, tsControl=ctrl)

(请注意,我降低了神经网络模型的灵活性,以尝试防止其过度拟合)

拟合模型后,我们可以通过MAPE比较它们(cv.ts尚不支持MASE):

res_overall <- lapply(models, function(x) x$results[13,-1])
res_overall <- Reduce(rbind, res_overall)
row.names(res_overall) <- names(models)
res_overall <- res_overall[order(res_overall[,'MAPE']),]
round(res_overall, 2)
                 ME    RMSE     MAE   MPE MAPE
naive     91.40 1126.83  961.18  0.19 2.40
ets       91.56 1127.09  961.35  0.19 2.40
stl     -114.59 1661.73 1332.73 -0.29 3.36
neural     5.26 1979.83 1521.83  0.00 3.83
bats     294.01 2087.99 1725.14  0.70 4.32
sts     -698.90 3680.71 1901.78 -1.81 4.77
arima  -1687.27 2750.49 2199.53 -4.23 5.53
tbats   -476.67 2761.44 2428.34 -1.23 6.10

哎哟。我们的结构预测似乎很幸运。从长远来看,幼稚的预测是最好的预测,在12个月的时间范围内平均(ARIMA模型仍然是最差的模型之一)。让我们比较一下12个预测范围中的每个模型,看看是否有一个模型能击败天真的模型:

library(reshape2)
library(ggplot2)
res <- lapply(models, function(x) x$results$MAPE[1:12])
res <- data.frame(do.call(cbind, res))
res$horizon <- 1:nrow(res)
res <- melt(res, id.var='horizon', variable.name='model', value.name='MAPE')
res$model <- factor(res$model, levels=row.names(res_overall))
ggplot(res, aes(x=horizon, y=MAPE, col=model)) +
  geom_line(size=2) + theme_bw() +
  theme(legend.position="top") +
  scale_color_manual(values=c(
    "#1f78b4", "#ff7f00", "#33a02c", "#6a3d9a",
    "#e31a1c", "#b15928", "#a6cee3", "#fdbf6f",
    "#b2df8a")
    )

模型比较

可以说,指数平滑模型总是选择朴素的模型(橙色线和蓝色线重叠100%)。换句话说,天真的“下个月的卷材价格将与本月的卷材价格相同”的预测(几乎在每个预测范围内)比7个极为复杂的时间序列模型更为准确。除非您掌握卷材市场尚不知道的秘密信息,否则要击败简单的卷材价格预测将非常困难

这绝不是任何人都想听到的答案,但是,如果预测精度是您的目标,则应使用最准确的模型。使用天真的模型。


看看这些模型之间的差异很有趣。NNAR特别看起来与众不同。鉴于这是一个著名的数据集(我相信它具有悠久的历史),是否知道哪个是正确的以及一种模型类型是否胜过其他模型?(Nb,我对TS知之甚少。)
gung-恢复莫妮卡

@gung做到这一点的最佳方法是拆分一个保留集并测试模型。需要注意的是,使最好的短期预测模型可能不是使最好的长期预报的模型....
扎克-

非常感谢,但是对于上述数据集我没有得到很好的预测(我想这里缺少一些重要的步骤)。您能告诉我是否遗漏了什么吗
Niranjan Sonachalam 2015年

@Niranjan您能告诉我们/显示您如何得出未得到良好预测的结论吗?
天气预报员

@forecaster:请在此处检查pbrd.co/1DRPRsq。我是新手。让我知道您是否需要任何特定信息。我尝试过有马模型。
Niranjan Sonachalam'3

12

您采用的方法是合理的。如果您不熟悉预测,那么我建议您阅读以下书籍:

  1. Makridakis,Wheelright和Hyndman的预测方法和应用
  2. 预测: Hyndman和Athanasopoulos的原则和实践

第一本书是我强烈推荐的经典。第二本书是一本开放源代码的书,您可以参考该书中的预测方法以及如何使用R开放源代码软件包预测来应用它 。这两本书都为我使用的方法提供了良好的背景。如果您对预测很认真,那么我建议您使用Armstrong 的预测原理,原理收集了大量关于预测的研究,从业者可能会发现它非常有用。

谈到您关于线圈的特定示例,它使我想起了大多数教科书经常忽略的可预测性概念。某些序列(例如您的序列)完全无法预测,因为它没有显示趋势或季节性变化或任何系统变化,因此模式较少。在那种情况下,我将一系列归类为较难预测。涉足外推方法之前,我想看看数据,并提出这样的问题,是我的一系列可预测的呢?在这个具体的例子,一个简单的外推,如随机游走预测其采用预测的最后一个值已经被认为是最准确的。

关于神经网络的另一条评论是:众所周知,神经网络在经验竞争中会失败。在尝试使用神经网络进行时间序列预测任务之前,我将尝试使用传统的时间序列统计方法。

我尝试在中建立您的数据模型R's forecast package,希望这些评论可以自我解释。

coil <- c(44000, 44500, 42000, 45000, 42500, 41000, 39000, 35000, 34000, 
          29700, 29700, 29000, 30000, 30000, 31000, 31000, 33500, 33500, 
          33000, 31500, 34000, 35000, 35000, 36000, 38500, 38500, 35500, 
          33500, 34500, 36000, 35500, 34500, 35500, 38500, 44500, 40700, 
          40500, 39100, 39100, 39100, 38600, 39500, 39500, 38500, 39500, 
          40000, 40000, 40500, 41000, 41000, 41000, 40500, 40000, 39300, 
          39300, 39300, 39300, 39300, 39800)


coilts <- ts(coil,start=c(2008,4),frequency=12)

library("forecast")

# Data for modeling
coilts.mod <- window(coilts,end = c(2012,3))

#Data for testing
coil.test <- window(coilts,start=c(2012,4))

# Model using multiple methods - arima, expo smooth, theta, random walk, structural time series

#arima
coil.arima <- forecast(auto.arima(coilts.mod),h=11)

#exponential smoothing
coil.ets <- forecast(ets(coilts.mod),h=11)

#theta
coil.tht <- thetaf(coilts.mod, h=11)

#random walk
coil.rwf <- rwf(coilts.mod, h=11)

#structts
coil.struc <- forecast(StructTS(coilts.mod),h=11)


##accuracy 

arm.acc <- accuracy(coil.arima,coil.test)
ets.acc <- accuracy(coil.ets,coil.test)
tht.acc <- accuracy(coil.tht,coil.test)
rwf.acc <- accuracy(coil.rwf,coil.test)
str.acc <- accuracy(coil.struc,coil.test)

在保留数据上使用MAE,我将选择ARIMA进行短期预测(1-12个月)。从长远来看,我将依靠随机游走预测。请注意,ARIMA选择了具有漂移(0,1,0)+漂移的随机游走模型,在这些类型的问题(尤其是短期问题)上,它比纯随机游走模型要准确得多。见下图。这是基于上面代码中所示的精度函数。

在此处输入图片说明

针对您的特定问题的具体答案:还有一个问题是,在传递给ARIMA或神经网络之前,我应该对数据进行平滑处理吗?如果是,使用什么?

  • 不,预测方法可以自然地使数据平滑以适应模型。

数据显示季节性和趋势。

  • 以上数据未显示趋势或季节性。如果确定数据显示季节性和趋势,则选择适当的方法。

提高准确性的实用技巧:

结合各种预测方法: -您可以尝试使用非外推方法,例如通过类比预测,判断性预测或其他技术进行预测,然后将其与统计方法结合使用以提供准确的预测。有关合并的好处,请参见本文。我尝试将上述5种方法结合起来使用,但是预测结果与单个方法相比并不准确,一个可能的原因是各个预测值相似。当您组合多种方法(例如统计和判断性预测)时,您将获得组合预测的好处。

检测并了解离群值: -现实世界数据充满了离群值。确定并适当地处理时间序列中的异常值。建议阅读这篇文章。在查看线圈数据时,2009年之前的跌幅是一个异常值吗?

编辑

该数据似乎遵循某种类型的宏观经济趋势。我的猜测是,2009年之前的下降趋势跟随着2008年至2009年之间的经济衰退,并在2009年之后开始回升。这些经济趋势表现得就像@GraemeWalsh所引用的那样。

希望这可以帮助

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.