Séries Temporais: Fundamentos e Decomposição
Insper, PADS
2026
Ao final do curso você será capaz de:
📝 Trabalho intermediário: 50% da nota
🎤 Trabalho final: 50% da nota
Parte 1: Fundamentos
Parte 2: Componentes e Decomposição
Parte 3: PACF e Modelos
Nota
Aula 2: SARIMA, Prophet e modelos de previsão com sazonalidade
Processo estocástico, autocorrelação e estacionariedade
Um processo estocástico é uma família de variáveis aleatórias indexadas pelo tempo:
\[X = \{X(t, \omega),\ t \in T,\ \omega \in \Omega\}\]
Nota
Cada trajetória \(X^{(i)}(t)\) é uma realização do processo.
A série temporal observada é uma dessas infinitas trajetórias possíveis.
Uma variável aleatória é uma função que associa a cada elemento \(\omega \in \Omega\) do espaço amostral um número real:
\[X: \Omega \to \mathbb{R}\]
Nota
Exemplo: ao jogar um dado não viciado, \(\Omega = \{1,2,3,4,5,6\}\) e definimos \(X\) como o resultado obtido, tal que \(P(X = k) = \frac{1}{6}\) para \(k = 1, \ldots, 6\).
Um processo estocástico é uma sequência de variáveis aleatórias: é exatamente o que ocorre ao jogar o dado 500 vezes e registrar os resultados consecutivos.
A Função de Autocorrelação (ACF) mede o grau de dependência linear entre \(Y_t\) e seus valores passados \(Y_{t-k}\):
\[\rho_k = \frac{\text{Cov}(Y_t,\, Y_{t-k})}{\text{Var}(Y_t)}\]
onde \(k\) é chamado de lag (defasagem).
Dica
Intuição: a ACF responde “o passado ajuda a prever o futuro?” Se sim → há memória na série. Se não → processo é i.i.d.
Quando as VAs são independentes e possuem a mesma distribuição de probabilidade, o processo é chamado i.i.d.:
Aviso
Observe que a ACF está toda dentro do intervalo de confiança, confirmando ausência de dependência temporal. Séries temporais reais não são i.i.d.: há memória entre os pontos!
Usaremos o IBC-Br (BCB, código 24363), proxy mensal do PIB brasileiro:
Nota
O IBC-Br é calculado mensalmente pelo Banco Central e funciona como
proxy do PIB antes da divulgação oficial pelo IBGE.
Instale com: pip install python-bcb
\[\rho_k = \text{Cor}(Y_t, Y_{t-k}) = \frac{\text{Cov}(Y_t, Y_{t-k})}{\text{Var}(Y_t)}\]
import matplotlib.pyplot as plt
from statsmodels.graphics.tsaplots import plot_acf
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
axes[0].plot(ibc.index, ibc['ibc'], color='#E4002B')
axes[0].set_title('IBC-Br: Índice Mensal (BCB 24363)')
plot_acf(ibc['ibc'], ax=axes[1], lags=24, title='ACF: Nível', zero=False)
plt.tight_layout(); plt.show()Dica
A ACF decai muito lentamente → sinal de não-estacionariedade. Os picos nos lags 12, 24, 36 revelam a sazonalidade anual da série.
Um processo é fracamente estacionário quando possui:
| Propriedade | Condição |
|---|---|
| Média | Constante para todo \(t\) |
| Variância | Constante para todo \(t\) |
| Covariância | Função apenas da defasagem |
Dica
A ACF do IBC-Br decai muito lentamente: sinal claro de não-estacionariedade e presença de raiz unitária.
Defasagem: \(y_{t-1},\ y_{t-2},\ \ldots\) | Diferenciação: \(\Delta y_t = y_t - y_{t-1}\)
\[y_t = y_{t-1} + \varepsilon_t, \quad \varepsilon_t \sim RB(0, \sigma^2)\]
Um ruído branco \(\{\varepsilon_t\}\) é um processo estocástico com:
| Propriedade | Condição |
|---|---|
| Média | \(E[\varepsilon_t] = 0\) |
| Variância | \(\text{Var}(\varepsilon_t) = \sigma^2\) (constante) |
| Covariância | \(\text{Cov}(\varepsilon_t, \varepsilon_s) = 0\ \forall\ t \neq s\) |
Nota
Ruído branco gaussiano = processo i.i.d. quando \(\varepsilon_t \sim \mathcal{N}(0, \sigma^2)\)
O ruído branco é o componente residual ideal de qualquer modelo de séries temporais: se os resíduos são ruído branco, o modelo capturou toda a estrutura da série.
Na notação: \[\varepsilon_t \sim RB(0, \sigma^2)\]
Tendência, sazonalidade, ciclo, resíduo, decomposição e teste ADF
A sazonalidade se manifesta como picos repetidos na ACF nos múltiplos do período \(s\):
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
# Série em nível
plot_acf(ibc['ibc'], ax=axes[0], lags=36,
title='ACF: IBC-Br Nível (picos a cada 12 lags)', zero=False)
# Série com 1ª diferença
plot_acf(ibc['ibc_diff'].dropna(), ax=axes[1], lags=36,
title='ACF: IBC-Br 1ª Diferença (ainda sazonal!)', zero=False)
plt.tight_layout(); plt.show()Dica
Na 1ª diferença os picos no lag 12, 24, 36 ainda são significativos: a sazonalidade não desaparece com uma simples diferença. É preciso também diferenciar sazonalmente.
\[\Delta\Delta_{12} y_t = \Delta y_t - \Delta y_{t-12}\]
Nota
A diferença sazonal \(\Delta_{12}\) reduz a sazonalidade, mas pode restar estrutura nos lags 12, 24, 36 da ACF. Modelos específicos tratam isso de forma sistemática.
| Modelo | Abordagem | Destaque |
|---|---|---|
| SARIMA | Parâmetros sazonais \(P\), \(D\), \(Q\) | Rigor estatístico |
| Prophet (Meta) | Decomposição + Fourier | Sazonalidades múltiplas |
| ETS | Suavização exponencial | Simples e robusto |
| TBATS | Box-Cox + Fourier | Sazonalidade complexa |
Dica
Na Aula 2 veremos como ajustar e comparar esses modelos na prática, incluindo SARIMA e Prophet para séries financeiras.
| Componente | O que é | Exemplo | Característica |
|---|---|---|---|
| Tendência | Movimento de longo prazo | PIB crescendo ao longo de décadas | Persistente, suave |
| Sazonalidade | Padrão em período fixo e conhecido | IBC-Br cai em jan (13º), sobe em dez | Período constante |
| Ciclo | Flutuações de período variável | Ciclos de expansão/recessão (3-10 anos) | Menos previsível |
| Resíduo | Variação após remover os demais | Choques imprevistos (Covid, greves) | Idealmente ruído branco |
Modelo Aditivo: \(Y_t = T_t + S_t + C_t + R_t\)
Dica
Tendência vs. Ciclo: na prática são difíceis de separar: muitos métodos os tratam juntos como “tendência-ciclo”. A sazonalidade, por ter período fixo, é mais fácil de isolar.
Aditivo vs. Multiplicativo: se o “zigue-zague” sazonal cresce com o nível da série → use multiplicativo (\(Y_t = T_t \times S_t \times R_t\)). Na dúvida, aplique log e use aditivo.
Nota
A crise de 2015-16 aparece na tendência; o choque do Covid no resíduo.
from statsmodels.tsa.stattools import adfuller
def rodar_adf(serie, nome):
k = int(np.floor((len(serie) - 1) ** (1/3)))
res = adfuller(serie, maxlag=k, autolag=None, regression='c')
print(f"ADF {nome}: stat={res[0]:.3f} | p-value={res[1]:.3f}")
rodar_adf(ibc['ibc'], 'IBC-Br: Nível')
rodar_adf(ibc['ibc_diff_seas'].dropna(), 'IBC-Br: Estacionarizado')Autocorrelação parcial, identificação e modelos AR/MA/ARIMA
A PACF mede a correlação entre \(Y_t\) e \(Y_{t-k}\) após remover o efeito dos lags intermediários:
\[\phi_{kk} = \text{Cor}(Y_t - \hat{Y}_t,\ Y_{t-k} - \hat{Y}_{t-k})\]
onde \(\hat{Y}_t\) é a projeção de \(Y_t\) sobre \(Y_{t-1}, \ldots, Y_{t-k+1}\).
Nota
Algoritmo de Levinson-Durbin:
| Padrão | ACF | PACF | Modelo |
|---|---|---|---|
| ACF corta | Corte em \(q\) | Decaimento | MA(\(q\)) |
| PACF corta | Decaimento | Corte em \(p\) | AR(\(p\)) |
| Ambas decaem | Decaimento | Decaimento | ARMA(\(p,q\)) |
| ACF não decai | Lento | Pico lag 1 | Não estacionário |
Aviso
Na prática, os padrões raramente são tão limpos! Use a tabela como ponto de partida, não diagnóstico definitivo. Critérios AICc são mais confiáveis.
O valor de hoje depende dos \(p\) valores passados:
\[Y_t = c + \phi_1 Y_{t-1} + \phi_2 Y_{t-2} + \cdots + \phi_p Y_{t-p} + \varepsilon_t\]
O valor de hoje depende dos \(q\) choques passados:
\[Y_t = \mu + \varepsilon_t + \theta_1 \varepsilon_{t-1} + \cdots + \theta_q \varepsilon_{t-q}\]
# AR(1), MA(1) e ARMA(1,1) simulados
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
fig, axes = plt.subplots(3, 2, figsize=(12, 9))
for row, serie in enumerate([ar1, ma1, arma11]):
plot_acf(serie, ax=axes[row, 0], lags=20, zero=False)
plot_pacf(serie, ax=axes[row, 1], lags=20, zero=False)
plt.tight_layout(); plt.show()from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
serie_est = ibc['ibc_diff_seas'].dropna()
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
plot_acf(serie_est, ax=axes[0], lags=24, title='ACF: IBC-Br Estacionarizado', zero=False)
plot_pacf(serie_est, ax=axes[1], lags=24, title='PACF: IBC-Br Estacionarizado', zero=False)
plt.tight_layout(); plt.show()Combina diferenciação com AR e MA:
\[\underbrace{(1 - \phi_1 B - \cdots - \phi_p B^p)}_{\text{AR}(p)} \underbrace{(1-B)^d}_{\text{I}(d)} Y_t = c + \underbrace{(1 + \theta_1 B + \cdots + \theta_q B^q)}_{\text{MA}(q)} \varepsilon_t\]
| Parâmetro | Significado | Como determinar |
|---|---|---|
| \(p\) | Ordem AR | PACF: corte em \(p\) |
| \(d\) | Nº de diferenças | Teste ADF |
| \(q\) | Ordem MA | ACF: corte em \(q\) |
Nota
O ARIMA captura séries não sazonais após diferenciação. Para sazonalidade explícita, a extensão natural é o SARIMA, tema da Aula 2.
Identificação: Plotar a série, ACF, PACF. Determinar \(d\) pelo teste ADF. Identificar \(p\) e \(q\) pela tabela ACF/PACF.
Estimação: Ajustar o modelo por máxima verossimilhança. Comparar candidatos via AICc (menor = melhor).
Diagnóstico: Verificar se os resíduos são ruído branco: ACF dos resíduos, teste Ljung-Box. Se não: voltar ao passo 1.
Previsão: Gerar previsões com intervalos de confiança.
Dica
O diagnóstico dos resíduos é o critério definitivo: se sobraram padrões, o modelo ainda não captou tudo.
O algoritmo Hyndman-Khandakar automatiza o Box-Jenkins:
from statsforecast import StatsForecast
from statsforecast.models import AutoARIMA
sf = StatsForecast(
models=[AutoARIMA(season_length=1)], # sem sazonalidade por enquanto
freq='MS',
n_jobs=1,
)
ibcbr_df = ibc[['ibc_diff']].dropna().reset_index()
ibcbr_df.columns = ['ds', 'y']
ibcbr_df['unique_id'] = 'ibcbr'
sf.fit(df=ibcbr_df)
previsao = sf.predict(h=12, level=[80, 95])Aviso
O AutoARIMA não substitui o entendimento do processo: use-o como validação da escolha manual. Na Aula 2 veremos sua extensão sazonal.
python_bcbForecasting: Principles and Practice (3ª ed.)
Hyndman & Athanasopoulos · 🔗 otexts.com/fpppy
Material do Curso
🔗 padsinsper.github.io/202634-fa
Financial Analytics · PADS · Insper · 2026
Financial Analytics · PADS · Insper