Procedimiento de análisis de series de tiempo y métodos que utilizan R

13

Estoy trabajando en un pequeño proyecto en el que intentamos predecir los precios de los productos básicos (petróleo, aluminio, estaño, etc.) para los próximos 6 meses. Tengo 12 variables para predecir y tengo datos de abril de 2008 a mayo de 2013.

¿Cómo debo ir sobre predicción? He hecho lo siguiente:

  • Datos importados como un conjunto de datos de Timeseries
  • La estacionalidad de todas las variables tiende a variar con la tendencia, por lo que voy al modelo multiplicativo.
  • Tomé el registro de la variable para convertirla en modelo aditivo
  • Para cada variable descompuesta los datos usando STL

Estoy planeando utilizar el suavizado exponencial de Holt Winters, ARIMA y la red neuronal para pronosticar. Dividí los datos como entrenamiento y pruebas (80, 20). Planeando elegir el modelo con menos MAE, MPE, MAPE y MASE.

¿Lo estoy haciendo bien?

También una pregunta que tuve fue, antes de pasar a ARIMA o red neuronal, ¿debo suavizar los datos? En caso afirmativo, ¿usando qué? Los datos muestran tanto la estacionalidad como la tendencia.

EDITAR:

Adjuntando el diagrama y los datos de la serie ingrese la descripción de la imagen aquí

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)

EDIT 2: Una pregunta, ¿podría decirme si mis datos tienen alguna estacionalidad o tendencia? Y también, por favor, dame algunos consejos sobre cómo identificarlos. ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

Niranjan Sonachalam
fuente
2
Si está tratando de pronosticar grupos de productos, como varios tipos de metal (acero A, acero B, acero C, etc.), entonces puede valer la pena probar la existencia de cointegración. Por ejemplo, algo como esto: ¿los precios del acero se mueven juntos? . Esto puede proporcionar mejores pronósticos de 6 meses (mediano / largo plazo) que los métodos univariados, pero este es, de hecho, un juego difícil que estás intentando jugar. ;-)
Graeme Walsh
1
Como señala @GraemeWalsh, la extrapolación de tendencia univariada podría no ser ideal para este tipo de datos. Existen métodos bien establecidos en la literatura para pronosticar los precios del petróleo y el acero que vale la pena explorar.
pronosticador
1
¿Puedes publicar nuevas ediciones como una pregunta separada? Como ya ha aceptado una respuesta, es posible que las nuevas preguntas no reciban la atención que necesita. Al observar los datos, puedo decir que ninguno de ellos tiene tendencias o patrones estacionales. Como se señala en mi publicación a continuación, ¿parece que la tendencia a la baja antes de 2009 es un fenómeno macroeconómico como la recesión?
pronosticador
@ pronosticador, @ GraemeWalsh: Gracias. Estoy planeando usar el método de cointegración usando pruebas ADF.
Niranjan Sonachalam
1
Has proporcionado contexto en tu nueva pregunta y ahora tiene más sentido. Entonces, la caída antes de 2009 fue de hecho algunos fenómenos macroeconómicos. En ese caso, utilice el método de caminata aleatoria con deriva o (arima (0,1,0) + deriva
pronosticador

Respuestas:

21

Debe usar el paquete de pronóstico , que admite todos estos modelos (y más) y hace que ajustarlos sea muy fácil:

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)

Aconsejaría no suavizar los datos antes de ajustar su modelo. Su modelo intentará inherentemente suavizar los datos, por lo que el preajuste solo complica las cosas.

ingrese la descripción de la imagen aquí

Edición basada en nuevos datos:

En realidad, parece que Arima es uno de los peores modelos que podría elegir para este conjunto de entrenamiento y prueba.

Guarde sus datos en una llamada de archivo coil.csv, los cargué en R y los dividí en un conjunto de entrenamiento y prueba:

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))

A continuación, me ajusto a un montón de modelos de series de tiempo: arima, suavizado exponencial, red neuronal, tbats, murciélagos, descomposición estacional y series de tiempo estructurales:

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)
  )

Luego hice algunos pronósticos y los comparé con el conjunto de prueba. Incluí un pronóstico ingenuo que siempre predice una línea plana y horizontal:

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')
}

ingrese la descripción de la imagen aquí

Como puede ver, el modelo arima se equivoca en la tendencia, pero me gusta el aspecto del "Modelo estructural básico"

Finalmente, medí la precisión de cada modelo en el conjunto de prueba:

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

Las métricas utilizadas se describen en Hyndman, RJ y Athanasopoulos, G. (2014) "Predicción: principios y práctica" , quienes también son los autores del paquete de predicción. Le recomiendo que lea su texto: está disponible de forma gratuita en línea. La serie de tiempo estructural es el mejor modelo por varias métricas, incluida MASE, que es la métrica que tiendo a preferir para la selección del modelo.

Una última pregunta es: ¿tuvo suerte el modelo estructural en este conjunto de pruebas? Una forma de evaluar esto es mirar los errores del conjunto de entrenamiento. Los errores del conjunto de entrenamiento son menos confiables que los errores del conjunto de prueba (porque pueden ser demasiado ajustados), pero en este caso el modelo estructural sigue siendo el primero:

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

(Tenga en cuenta que la red neuronal se sobreajusta, con un rendimiento excelente en el conjunto de entrenamiento y mal en el conjunto de prueba)

Finalmente, sería una buena idea hacer una validación cruzada de todos estos modelos, tal vez entrenando en 2008-2009 / probando en 2010, entrenando en 2008-2010 / probando en 2011, entrenando en 2008-2011 / probando en 2012, entrenando en 2008-2012 / pruebas en 2013, y promediando errores en todos estos períodos de tiempo. Si deseas seguir esa ruta, tengo un paquete parcialmente completo para la validación cruzada de modelos de series temporales en github que me encantaría que pruebe y me envíe comentarios / solicitudes de extracción sobre:

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

Edición 2: ¡Veamos si recuerdo cómo usar mi propio paquete!

En primer lugar, instale y cargue el paquete desde github (ver arriba). Luego, realice una validación cruzada de algunos modelos (utilizando el conjunto de datos completo):

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)

(Tenga en cuenta que reduje la flexibilidad del modelo de red neuronal, para tratar de ayudar a evitar que se ajuste demasiado)

Una vez que hayamos ajustado los modelos, podemos compararlos por MAPE (cv.ts aún no admite 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

Ay. Parece que nuestro pronóstico estructural tuvo suerte. A largo plazo, el pronóstico ingenuo hace los mejores pronósticos, promediados en un horizonte de 12 meses (el modelo arima sigue siendo uno de los peores modelos). Comparemos los modelos en cada uno de los 12 horizontes de pronóstico y veamos si alguno de ellos supera al modelo ingenuo:

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")
    )

comparar modelo

De manera reveladora, el modelo de suavizado exponencial siempre elige el modelo ingenuo (la línea naranja y la línea azul se superponen al 100%). En otras palabras, el pronóstico ingenuo de "los precios de la bobina del próximo mes será el mismo que los precios de la bobina de este mes" es más preciso (en casi todos los horizontes de pronóstico) que 7 modelos de series temporales extremadamente sofisticados. A menos que tenga alguna información secreta que el mercado de bobinas aún no conoce, superar el ingenuo pronóstico del precio de la bobina será extremadamente difícil .

Nunca es la respuesta que alguien quiere escuchar, pero si su objetivo es la precisión del pronóstico, debe usar el modelo más preciso. Usa el modelo ingenuo.

Zach
fuente
Es interesante observar las diferencias entre estos modelos. NNAR en particular se ve diferente. Dado que este es un conjunto de datos famoso (e históricamente antiguo, creo), ¿se sabe cuál es el correcto y si un tipo de modelo tiene un rendimiento superior? (Nb, sé relativamente poco acerca de TS.)
Gung - Restablecer Monica
@gung La mejor manera de hacer esto sería dividir un conjunto de reserva y probar el modelo. Tenga en cuenta que el modelo que hace los mejores pronósticos a corto plazo puede no ser el modelo que hace los mejores pronósticos a largo plazo ...
Zach
Muchas gracias, pero no estoy obteniendo buenos pronósticos para el conjunto de datos anterior (creo que me estoy perdiendo algún paso importante aquí). ¿Me puede decir si me falta algo
Niranjan Sonachalam
@Niranjan ¿Puede decirnos / mostrar cómo concluye que no está obteniendo un buen pronóstico?
pronosticador
@forecaster: compruebe aquí pbrd.co/1DRPRsq . Soy nuevo en el pronóstico. Avísame si necesitas información específica. Lo intenté con el modelo Arima.
Niranjan Sonachalam
12

El enfoque que ha tomado es razonable. Si eres nuevo en el pronóstico, te recomendaría los siguientes libros:

  1. Métodos y aplicaciones de pronóstico por Makridakis, Wheelright y Hyndman
  2. Pronósticos: Principios y práctica de Hyndman y Athanasopoulos.

El primer libro es un clásico que recomiendo encarecidamente. El segundo libro es un libro de código abierto que puede consultar para conocer los métodos de pronóstico y cómo se aplica utilizando el pronóstico delR paquete de software de código abierto . Ambos libros proporcionan buenos antecedentes sobre los métodos que he usado. Si se toma en serio la predicción, entonces recomendaría Principios de predicción de Armstrong, que es una recopilación de una enorme cantidad de investigación en predicción que los profesionales pueden encontrar muy útil.

Al llegar a su ejemplo específico en la bobina, me recuerda un concepto de capacidad de predicción que la mayoría de los libros de texto a menudo ignoran. Algunas series, como su serie, simplemente no se pueden pronosticar porque es un patrón menos, ya que no exhibe tendencias o patrones estacionales o cualquier variación sistemática. En ese caso, clasificaría una serie como menos predecible. Antes de aventurarse en los métodos de extrapolación, me gustaría ver los datos y hacer la pregunta, es mi serie predecibles? En este ejemplo específico, una simple extrapolación como paseo aleatorio pronóstico que utiliza el último valor de la previsión se ha encontrado para ser más preciso .

También un comentario adicional sobre la red neuronal: se sabe que las redes neuronales fallan en las competiciones empíricas . Probaría métodos estadísticos tradicionales para series de tiempo antes de intentar usar redes neuronales para tareas de pronóstico de series de tiempo.

Intenté modelar sus datos R's forecast package, espero que los comentarios se expliquen por sí mismos.

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)

Usando MAE en los datos retenidos, elegiría ARIMA para el pronóstico a corto plazo (1 - 12 meses). a largo plazo, confiaría en el pronóstico de caminata aleatoria. Tenga en cuenta que ARIMA eligió un modelo de caminata aleatoria con deriva (0,1,0) + deriva que tiende a ser mucho más precisa que el modelo de caminata aleatoria pura en este tipo de problemas específicamente a corto plazo. Ver abajo la tabla. Esto se basa en la función de precisión como se muestra en el código anterior.

ingrese la descripción de la imagen aquí

Respuestas específicas a sus preguntas específicas: También una pregunta que tuve fue, antes de pasar a ARIMA o red neuronal, ¿debo suavizar los datos? En caso afirmativo, ¿usando qué?

  • No, los métodos de pronóstico suavizan naturalmente sus datos para que se ajusten al modelo.

Los datos muestran tanto la estacionalidad como la tendencia.

  • Los datos anteriores no muestran tendencia o estacionalidad. Si determina que los datos exhiben estacionalidad y tendencia, elija un método apropiado.

Consejos prácticos para mejorar la precisión:

Combine una variedad de métodos de pronóstico: - Puede intentar usar métodos que no sean de extrapolación, como el pronóstico por analogía , el pronóstico crítico u otras técnicas, y combinarlos con sus métodos estadísticos para proporcionar predicciones precisas. Vea este artículo para conocer los beneficios de combinar. Intenté combinar los 5 métodos anteriores, pero la predicción no fue precisa como métodos individuales, una posible razón es que los pronósticos individuales son similares. Usted cosecha los beneficios de combinar pronósticos cuando combina diversos métodos, como pronósticos estadísticos y críticos.

Detectar y comprender valores atípicos: - Los datos del mundo real están llenos de valores atípicos. Identificar y tratar adecuadamente los valores atípicos en series de tiempo. Recomiendo leer esta publicación . Al mirar los datos de su bobina, ¿la caída anterior a 2009 es un valor atípico?

Editar

Los datos parecen estar siguiendo algún tipo de tendencias macroeconómicas. Mi conjetura es que la tendencia a la baja vista antes de 2009 sigue a la caída de la economía vista entre 2008 y 2009 y comienza a recuperarse después de 2009. Si este es el caso, entonces evitaría usar métodos de extrapolación y en su lugar confiaría en una teoría sólida sobre cómo Estas tendencias económicas se comportan como la referenciada por @GraemeWalsh.

Espero que esto ayude

pronosticador
fuente