ME607 - Séries Temporais
Instituto de Matemática, Estatística e Computação Científica (IMECC),
Universidade Estadual de Campinas (UNICAMP).
Todo projeto relacionado com séries temporais deve passar pelo seguinte fluxo:
Os modelos básicos são bastante simples, para explicar eles, bem como para ilustrar como especificar e estimar o modelo no R, utilizaremos alguns métodos simples.
Rows: 58
Columns: 2
$ Year <int> 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 197…
$ GDP_pc <dbl> 210.0275, 204.9293, 260.2253, 291.9506, 261.3311, 260.9647, 315…
\[\hat{y}_{T+h|T} = \dfrac{\sum_{i=1}^T y_i}{T}\]
\[\text{Naive } \equiv \text{ Ingênuo}\]
Todas as previões são iguais à última observação, \(\hat{y}_{T+h|T} = y_T\).
As previões são iguais à última observação do mesmo período sazonal.
Para ilustrar o método, vamos supor que nossos dados possuem um período sazonal \(m = 10\), ou seja que de 10 em 10 anos existe um padrão sazonal.
O drift (quantidade de mudança ao longo do tempo) é calculado como a mudança média nos dados históricos, \(\hat{y}_{T+h|T} = y_T + \dfrac{h}{T-1} \displaystyle \sum_{t=2}^T (y_t-y_{t-1}) = y_T + h \Big( \dfrac{y_T - y_1}{T-1} \Big)\).
Repare na sintaxe da forma model(nome_qqr = nome_do_modelo(y ~ x))
Note que “saber o código” não isenta de sabermos quando utilizar um modelo. Por exemplo, no slide anterior utilizamos a média para uma série não estacionária. (o que não parece ser uma boda ideia, certo?). Consegue pensar um caso em que utilizar a média não pareça uma ideia tão ruim?
Para responder isto, faremos um diagnóstico do modelo e avaliaremos o desempenho fora da amostra
Através dos resíduos de inovação saberemos se o modelo capturo a dinâmica dos dados.
Assim como o médico é capaz de fazer um diagnóstico do paciente baseando-se nos resultados dos exames médicos. Nós, somos capazes de fazer um diagnóstico do modelo através da análise dos resíduos de inovação.
Em geral, queremos os resíduos de innovação sejam um ruido branco com média zero.
Um processo \(\{ \epsilon_t \}\) é chamado de ruido branco se é uma sequência de variáveis aleatórias de distribuição fixa com \(\mathbb{E}(\epsilon_t) = 0\), \(\mathbb{V}(\epsilon_t) = \sigma^2\) e \(\gamma(k) = 0 \quad \forall k\).
# Importando os dados
uri <- "https://raw.githubusercontent.com/ctruciosm/ctruciosm.github.io/master/datasets/lajeado_rs.csv"
lajeado_rs <- read.csv(uri, sep = ";")
# Passando para um formato de séries temporais
lajeado_rs <- lajeado_rs %>%
mutate(ano_mes = yearmonth(ano_mes)) %>%
select(ano_mes, temp_media) %>%
as_tsibble(index = ano_mes)
glimpse(lajeado_rs)
Rows: 79
Columns: 2
$ ano_mes <mth> 2015 Jan, 2015 Feb, 2015 Mar, 2015 Apr, 2015 May, 2015 Jun,…
$ temp_media <dbl> 25.6, 24.8, 24.2, 21.2, 18.5, 16.2, 15.9, 21.0, 17.8, 19.4,…
A função gg_tsresiduals()
do pacote feasts
(que já é carregado quando utilizamos o pacote fpp3
) nos ajudará a fazer o diagnóstico do modelo. A função fornece o gráfico de sequência, o gráfico da função de autocorrelação e o histograma dos resíduos de inovação.
Embora o gráfico da função de autocorrelação (também conhecido como correlograma) nos ajude a verificar se os resídios são ou não correlacionados, muitas vezes é dificil verificar isto visualmente.
\[H_0: \rho_1 = \rho_2 = \cdots = \rho_k = 0.\]
\[Q = T \displaystyle \sum_{i=1}^k \hat{\rho}_i^2 \sim \chi^2_{k-q}\]
\[Q^{\ast} = T(T+2) \displaystyle \sum_{i=1}^k (T-i)^{-1} \hat{\rho}_i^2 \sim \chi^2_{k-q}\]
em que \(\hat{\rho}_i = \widehat{\mathbb{Cov}}(\hat{\epsilon}_t, \hat{\epsilon}_{t-i})\), \(k\) é o número de desafagens utilizado (usualmente 10 para dados não sazonais ou \(2 \times m\) para dados com período sazonal \(m\)) e \(q\) é o número de parâmetros estimados no modelo.
Se a série for um ruido branco, \(\hat{\rho}_i \approx 0\) e então \(Q\) (ou \(Q^{\ast}\)) serão pequenos. Valores muito grandes de \(Q\) (ou \(Q^{\ast}\)) levarão a rejeitar \(H_0\).
No exemplo da temperatura de Lajeado/RS, temos sazonalidade mensal (\(m = 12\)), assim \(k = 2 \times 12\). Como o modelo SNAIVE não estima parâmetros (apenas repete as últimas observações do período sazonal), \(q = 0\).
Observação: a função augment()
fornece os valores estimados (.fitted), os resíduos (.resid) e os resíduos de inovação (.innov). São os resíduos de inovação que estão entrando como argumento na função features()
que por sua vez calcular os testes desejados.
Box-Pierce test
data: residuos$.innov
X-squared = 30.972, df = 24, p-value = 0.1546
Box-Ljung test
data: residuos$.innov
X-squared = 38.224, df = 24, p-value = 0.03288
Embora os dois testes sejam bastante utilizados, o teste de Ljung-Box é preferido.
Outras características desejáveis nos resíduos de innovação são:
fit %>% gg_tsresiduals()
Em lugar de utilizarmos treinamento e teste uma única vez, faremos isto várias vezes!
Conhecido também como expanding/stretching window.
Conhecido também como rolling window.
E se quisermos uma medida de quão bem está performando o modelo?
\[\underbrace{MAE_i = \dfrac{1}{K}\displaystyle\sum_{k = 1}^{K} |e_{T_k+i}^k|}_{\text{Erro absoluto médio}} \quad e \quad \underbrace{RMSE_i = \sqrt{\dfrac{1}{K}\displaystyle\sum_{k = 1}^{K} (e_{T_k+i}^{k})^2}}_{\text{Raíz do erro quadrático médio}}, \quad i = 1, \cdots, h.\].
Outras medidas também utilizadas são:
Em que
\[\underbrace{q_{T_k+i}^k = \dfrac{e_{T_k+i}^k}{\dfrac{1}{T_k-1} \displaystyle \sum_{t = 2}^{T_k} |y_t - y_{t-1}|}}_{\text{Para dados não sazonais}} \quad ou \quad \underbrace{q_{T_k+i}^k = \dfrac{e_{T_k+i}}{\dfrac{1}{T_k-m} \displaystyle \sum_{t = m+1}^{T_k} |y_t - y_{t-m}|}}_{\text{Para dados sazonais}}\]
Quando comparamos modelos, o melhor modelo (i.e. faz uma melhor previsão) é aquele com menor MAE, RMSE, MAPE, sMAPE, MASE ou RMSSE.
No R, utilizaremos a função stretch_tsibble()
que nos ajudará a criar vários conjuntos de treinamento. O argumento .init
define quantas observações utilizaremos no primeiros conjunto de treinamento e .step
define o incremento no tamanho de amostra
Para ilustrar o que acontece quando utilizamos a função stretch_tsibble()
com .init = 3
e .step = 1
.
Rows: 3,157
Columns: 3
Key: .id [77]
$ ano_mes <mth> 2015 Jan, 2015 Feb, 2015 Mar, 2015 Jan, 2015 Feb, 2015 Mar,…
$ temp_media <dbl> 25.6, 24.8, 24.2, 25.6, 24.8, 24.2, 21.2, 25.6, 24.8, 24.2,…
$ .id <int> 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5,…
Ajustar (treinar) um modelo com apenas 3 observações não parece ser algo muito sensato. Utilizaremos .init = 50
para nosso exemplo.
# A tsibble: 6 x 2 [1M]
ano_mes temp_media
<mth> <dbl>
1 2015 Jan 25.6
2 2015 Feb 24.8
3 2015 Mar 24.2
4 2015 Apr 21.2
5 2015 May 18.5
6 2015 Jun 16.2
Rows: 1,935
Columns: 3
Key: .id [30]
$ ano_mes <mth> 2015 Jan, 2015 Feb, 2015 Mar, 2015 Apr, 2015 May, 2015 Jun,…
$ temp_media <dbl> 25.6, 24.8, 24.2, 21.2, 18.5, 16.2, 15.9, 21.0, 17.8, 19.4,…
$ .id <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
# A tibble: 1 × 10
.model .type ME RMSE MAE MPE MAPE MASE RMSSE ACF1
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 RW(temp_media ~ drift(… Test -0.285 2.45 1.98 -2.29 10.5 1.44 1.38 0.356
# A tibble: 3 × 11
h .model .type ME RMSE MAE MPE MAPE MASE RMSSE ACF1
<int> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 RW(temp_media ~ … Test -0.285 2.45 1.98 -2.29 10.5 1.44 1.38 0.356
2 2 RW(temp_media ~ … Test -0.521 4.13 3.59 -4.98 18.8 2.62 2.32 0.756
3 3 RW(temp_media ~ … Test -0.695 5.81 5.10 -8.11 26.9 3.73 3.27 0.793
As medidas de desempenho (MAE, RMSE, MAPE, etc) são bastante úteis quando temos vários modelos e queremos comparar o desempenho deles.
# A tibble: 4 × 10
.model .type ME RMSE MAE MPE MAPE MASE RMSSE ACF1
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 drif Test -0.285 2.45 1.98 -2.29 10.5 1.44 1.38 0.356
2 media Test -0.409 3.93 3.43 -6.02 18.2 2.51 2.21 0.760
3 naive Test -0.362 2.44 1.97 -2.73 10.5 1.44 1.37 0.357
4 snaive Test -0.197 1.51 1.17 -1.18 5.98 0.854 0.847 -0.0161
Será que o modelo SNAIVE, que obteme as melhores métricas de desempenho fora-da-amostra, capturou bem a dinâmica dos dados?.
stretch_tsibble()
faz expanding window e consome bastante memoria, sendo não recomendável para séries grandes.tile_tsibble()
.for()
, o que permite controlar se quisermos expanding ou rolling window (e traz maior flexibilidade caso queiramos utilizar outros pacotes do R).Rows: 79
Columns: 3
Key: .id [27]
$ ano_mes <mth> 2015 Jan, 2015 Feb, 2015 Mar, 2015 Apr, 2015 May, 2015 Jun,…
$ temp_media <dbl> 25.6, 24.8, 24.2, 21.2, 18.5, 16.2, 15.9, 21.0, 17.8, 19.4,…
$ .id <int> 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7,…
Carlos Trucíos (IMECC/UNICAMP) | ME607 - Séries Temporais | ctruciosm.github.io