Capítulo 6 Modelos ARIMA

Modelos ARIMA são outra classe de modelos populares em forecasting. A diferença entre modelos de suavização exponencial e os ARIMA é que os primeiros são baseados em descrever a tendência e a sazonalidade na série, enquanto os segundos se baseam em autocorrelações presentes nos dados.

Para este capítulo, continuaremos usando a série temporal do consumo de energia pela indústria no Brasil.

library(forecast)
library(tidyverse)
energia <- readRDS("data/ts_energia.Rda")

Antes de explicar o que é ARIMA, precisamos introduzir conceitos básicos como estacionariedade.

6.1 Estacionariedade, diferenciação e autocorrelação

Uma série temporal é dita estacionária se suas propriedades (média, variância, etc.) não dependem do tempo da observação. Portanto, séries que apresentam tendência ou sazonalidade não são estacionárias. Por outro lado, uma série composta por valores gerados aleatoriamente (ex. pela função rnorm) são estacionárias, visto que a “aparência” da série é basicamente a mesma para qualquer período \(t\).

A série abaixo é estacionária?
data("lynx")
head(lynx)
## Time Series:
## Start = 1821 
## End = 1826 
## Frequency = 1 
## [1]  269  321  585  871 1475 2821
autoplot(lynx)

Por curiosidade, linces são isto:

Aparentemente, a série apresenta ciclos ou sazonalidade, certo? Vamos ver seus componentes por dentro:

lynx %>% decompose() %>% autoplot()
## Error in decompose(.): time series has no or less than 2 periods
lynx %>% stl(s.window = "periodic") %>% autoplot()
## Error in stl(., s.window = "periodic"): series is not periodic or has less than two periods

Por que a função retorna um erro? Acontece que esta série não possui sazonalidade. Os algoritmos de decomposição não foram capazes de detectar períodos em que padrões se repetem, visto que os ciclos, além de possuírem níveis não constantes, acontecem em diferentes períodos, tornando-os imprevisíveis.

Voltando a nossa série de exemplo. Ela é estacionária?

energia %>% autoplot()

Claramente, ela não é. Contudo, existe um método muito simples para a tornar estacionária, que é a diferenciação. Ele se baseia nada mais em calcular a diferença absoluta (ou percentual) entre uma observação e a outra. O intervalo entre as observações pode ser escolhido pelo usuário:

head(energia, 10)
##       Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct
## 1980 4806 4808 4833 4901 5009 5162 5149 5432 5369 5391
head(diff(energia), 10)
##      Feb Mar Apr May Jun Jul Aug Sep Oct Nov
## 1980   2  25  68 108 153 -13 283 -63  22 114
head(diff(energia, 2), 10)
##       Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec
## 1980   27   93  176  261  140  270  220  -41  136 -270
# plotando as series
par(mfrow=c(3,1))
plot(energia, main = "Série original", xlab = "", ylab =  "")
plot(diff(energia), main  = "Série diferenciada", xlab = "", ylab =  "")
# plotando uma serie aleatoria:
plot(rnorm(length(energia)), type = "l", main = "Dados aleatórios", xlab = "", ylab = "")

Vemos pelo gráfico que a série diferenciada se aproxima muito de dados gerados aleatoriamente, comprovando que o método da diferenciação tornou a série estacionária.

Uma outra maneira de analisar a estacionariedade de uma série é pelo conceito de autocorrelação, que é uma medida do relacionamento linear entre os valores dentro de uma mesma série (como se fosse uma correlação interna). A autocorrelação depende do lag que se deseja analisar. Por exemplo, \(r1\) se refere à relação entre \(y_t\) e \(y_{t-1}\).

A melhor maneira de se analisar a autocorrelação de uma série é por meio de gráficos:

lag.plot(energia, lags = 9)

No gráfico de dispersão acima, vimos que em todos os 9 lags analisados, existe uma correlação forte entre as observações entre si. Numericamente, temos:

Acf(energia, plot = FALSE)$acf %>% as.vector()
##  [1] 1.0000000 0.9895288 0.9793583 0.9701326 0.9616287 0.9539380 0.9469652
##  [8] 0.9401798 0.9345256 0.9296718 0.9265290 0.9244649 0.9207918 0.9112844
## [15] 0.9016482 0.8932005 0.8856901 0.8792969 0.8726764 0.8664785 0.8610202
## [22] 0.8551207 0.8509758 0.8480218 0.8431056 0.8330215 0.8226599

Outro gráfico muito útil para analisar a autocorrelação é o próprio gráfico de autocorrelação, também conhecido como correlograma:

Acf(energia)

A linha horizonal tracejada azul define o nível de significância mínimo. Isto é, se uma autocorrelação estiver acima dessa linha, ela é estatisticamente significativa.

Contudo, a situação é diferente para a série diferenciada, como mostram os gráficos abaixo:

lag.plot(diff(energia), lags = 9)

Acf(diff(energia))

O fato de ainda haver três valores podem indicar duas coisas:

  • Que a série diferenciada ainda não é estacionária;
  • Que a série diferenciada é sim estacionária, pois esses lags com forte autocorrelação podem ser devidos a uma aleatoriedade. De fato, espera-se que, para uma série aleatória, 5% dos valores na ACF encontrem-se fora do intervalo \(\pm 2/ \sqrt{T}\).

6.2 Modelos autoregressivos

A diferença entre modelos regressivos e autoregressivos é que os primeiros prevêem o valor de uma variável de interesse usando uma combinação linear (equação) das variáveis explanatórias. Já os segundos usam uma combinação linear de valores passados da própria variável. Matematicamente, um modelo autoregressivo é descrito como:

\(y_t = c + \phi_1y_{t-1} + \phi_2y_{t-2} + ... + \phi_py_{t-p} + e_t\)

Onde \(c\) é uma constante e \(e_t\) é um erro aleatório (ruído branco). Esse tipo de modelo é chamado de modelo AR(p) e são normalmente restritos a séries estacionárias.

No R, modelos autoregressivos podem ser ajustados por meio da função arima:

# explicaremos o que é o argumento order da função abaixo daqui a pouco
ar.p1 <- energia %>% diff() %>% arima(order = c(1, 0, 0))
ar.p2 <- energia %>% diff() %>% arima(order = c(2, 0, 0))
coefficients(ar.p1) %>% round(4)
##       ar1 intercept 
##   -0.0130   19.2715
coefficients(ar.p2) %>% round(4)
##       ar1       ar2 intercept 
##   -0.0140   -0.0822   19.2385

Portanto, as equações resultantes do ajuste de modelos autoregressivos de ordem 1 e 2 são, respectivamente:

\(y_t = 21.1135 - 0.0135y_{t-1} + e_t\)

\(y_t = 20.9643 - 0.01435y_{t-1} - 0.0143y_{t-2} + e_t\)

6.3 Modelos de média móvel

Modelos de média móvel utilizam valores passados de erro de previsão de maneira semelhante a um modelo de regressão:

\(y_t = c + e_t + \theta_1e_{t-1} + \theta_2e_{t-2} + ... + \theta_qe_{t-q}\)

Um modelo acima é chamado de modelo MA(q) e pode ser interpretado como um modelo onde \(y_t\) é uma média ponderada dos erros de previsão passados.

6.4 Modelos ARIMA

A combinação entre os métodos de diferenciação e os modelos de autoregressão e média móvel resultam em um modelo ARIMA (AutoRegressive Integrated Moving Average model) não-sazonal, que pode ser descrito matematicamente como:

\(\acute{y_t} = c + \phi_1\acute{y}_{t-1} + ... + \phi_p\acute{y}_{t-p} + \theta_1 + \theta_1e_{t-1} + ... + \theta_qe_{t-q} + e_t\)

Onde \(\acute{y}_t\) é a série diferenciada. A equação acima é o que descreve o modelo ARIMA(p, d, q), onde:

  • \(p\) é a ordem do modelo autoregressivo;
  • \(d\) é o grau de diferenciação;
  • \(q\) é a ordem do modelo de média móvel.

Como seria complicado selecionar valores apropriada para cada um desses três parâmetros, a função forecast::auto.arima() faz isso automaticamente:

mod.arima <- auto.arima(energia, seasonal = FALSE)
summary(mod.arima)
## Series: energia 
## ARIMA(1,1,2) with drift 
## 
## Coefficients:
##          ar1      ma1      ma2    drift
##       0.6842  -0.7456  -0.1086  19.4967
## s.e.  0.0798   0.0866   0.0525   7.2082
## 
## sigma^2 estimated as 113359:  log likelihood=-3400
## AIC=6810.01   AICc=6810.14   BIC=6830.77
## 
## Training set error measures:
##                     ME     RMSE      MAE         MPE   MAPE      MASE
## Training set 0.2500474 334.8969 253.1834 -0.02693067 2.5143 0.4598817
##                     ACF1
## Training set 0.003546764

O modelo resultante é um ARIMA(2, 1, 1), o que corresponde a uma combinação a uma série com um grau de diferenciação (p = 1) aplicada em um modelo AR(2) e em um MA(1).

É possível saber o comportamento da previsão de um modelo ARIMA apenas baseado nos valores dos coeficientes c e d:

  • Se \(c = 0\) e \(d = 0\), previsões em longo prazo serão iguais a zero;
  • Se \(c = 0\) e \(d = 1\), serão iguais a uma constante maior que zero;
  • Se \(c \neq 0\) e \(d = 2\), seguirão uma linha reta;
  • Se \(c \neq 0\) e \(d = 0\), convergirão para a média da série;
  • Se \(c \neq 0\) e \(d = 1\), seguirão uma linha reta;
  • Se \(c \neq 0\) e \(d = 2\), seguirão uma tendência quadrática;

No caso do nosso exemplo, vamos ver se isso se aplica:

mod.arima %>% forecast(h = 36) %>% autoplot()

Conforme esperado, as previsões seguem uma linha reta, o que, em palavras, indicam que a série crescerá indefinitivamente.

Como ficaram as previsões de outras combinações ARIMA? Vamos fazer o teste:

# criar funcao para extrair previsao de um modelo arima
prever.arima <- function(p = 0, d, q = 0, con) {
  # argumento c = binario TRUE ou FALSE
  # argumento d = 0, 1 ou 2
  x <- Arima(energia, order = c(p, d, q), include.constant = con, seasonal = c(0, 0, 0))
  x <- forecast(x)
  as.numeric(x$mean)
}

# plotar previsoes
prever.arima(d = 1, con = FALSE)  %>% plot(type =  "l")
prever.arima(d = 0, con = FALSE) %>% lines(col = "red")
prever.arima(d = 2, con = FALSE) %>% lines(col = "orange")
prever.arima(d = 0, con = TRUE) %>% lines(col = "green")
prever.arima(d = 1, con = TRUE) %>% lines(col = "pink")
prever.arima(d = 2, con = TRUE) %>% lines(col = "blue")

6.5 Modelos SARIMA

Modelos ARIMA são capazes também de modelar séries que apresentam um componente sazonal, sendo descrito como:

ARIMA \((p, d, q)(P, D, Q)_m\)

Onde o primeiro parênteses se refere à parte não-sazonal do modelo e o segundo à parte sazonal. \(m\) corresponde ao número de períodos sazonais.

Ajustar um modelo SARIMA é semelhante ao processo de ajustar um ARIMA:

mod.sarima <- auto.arima(energia, seasonal = TRUE)
mod.sarima
## Series: energia 
## ARIMA(1,0,1)(0,1,2)[12] with drift 
## 
## Coefficients:
##          ar1      ma1     sma1     sma2    drift
##       0.9655  -0.1093  -0.6945  -0.1370  20.3127
## s.e.  0.0137   0.0465   0.0470   0.0458   4.8901
## 
## sigma^2 estimated as 68706:  log likelihood=-3211.86
## AIC=6435.72   AICc=6435.9   BIC=6460.49
mod.sarima %>% forecast(h = 36) %>% autoplot()

Para a série de análise, qual modelo possui o melhor ajuste: o sazonal ou o não-sazonal?

# calculando a qualidade de ajuste:
list(mod.arima, mod.sarima) %>% map(accuracy)
## [[1]]
##                     ME     RMSE      MAE         MPE   MAPE      MASE
## Training set 0.2500474 334.8969 253.1834 -0.02693067 2.5143 0.4598817
##                     ACF1
## Training set 0.003546764
## 
## [[2]]
##                    ME     RMSE      MAE          MPE     MAPE      MASE
## Training set 1.518877 257.3437 187.2863 0.0006205425 1.888167 0.3401863
##                      ACF1
## Training set -0.002581607
# calculando a qualidade preditiva
treino <- window(energia, end = c(2015, 12))
teste <- window(energia, start = c(2016, 1))

mod.arima2 <- auto.arima(treino, seasonal = FALSE) %>% forecast(teste)
## Warning in 1:h: numerical expression has 39 elements: only the first used
mod.sarima2 <- auto.arima(treino, seasonal = TRUE) %>% forecast(teste)

list(mod.arima2, mod.sarima2) %>% map(forecast) %>% map(accuracy, teste)
## [[1]]
##                      ME     RMSE      MAE         MPE     MAPE      MASE
## Training set   0.290353 326.0823 246.5337 -0.02778075 2.491441 0.4303939
## Test set     164.165281 367.2520 325.1233  1.12888967 2.343479 0.5675941
##                    ACF1 Theil's U
## Training set -0.0981782        NA
## Test set      0.4006154  1.033457
## 
## [[2]]
##                       ME      RMSE       MAE         MPE      MAPE
## Training set    4.834388  279.3321  205.7491  0.04012374  2.137084
## Test set     1544.035378 1710.4150 1555.9073 11.01891349 11.113601
##                   MASE         ACF1 Theil's U
## Training set 0.3591928 -0.002323165        NA
## Test set     2.7162735  0.850060508  5.025037

Apesar de o modelo ARIMA possuir o pior qualidade de ajuste, seu desempenho para prever valores futuros é superior ao SARIMA.