Phase 02 - Lesson 15
Fundamentos de séries temporais
This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.
O desempenho passado prevê resultados futuros – se você verificar primeiro a estacionariedade.
Tipo: Construir Idioma: Python Pré-requisitos: Fase 2, Lições 01-09 Tempo: ~90 minutos
Objetivos de aprendizagem
- Decompor uma série temporal em componentes de tendência, sazonalidade e resíduos e testar a estacionariedade
- Implementar recursos de atraso e estatísticas contínuas para converter uma série temporal em um problema de aprendizagem supervisionada
- Construir uma estrutura de validação passo a passo que evite que dados futuros vazem para o treinamento
- Explicar por que divisões aleatórias de treinamento/teste são inválidas para séries temporais e demonstrar a diferença de desempenho em relação às divisões temporais adequadas
O problema
Você tem dados ordenados por tempo. Vendas diárias, temperatura horária, uso de CPU por minuto, preços de ações semanais. Você deseja prever o próximo valor, a próxima semana, o próximo trimestre.
Você acessa seu kit de ferramentas de ML padrão: divisão aleatória de treinamento/teste, validação cruzada, entrada de matriz de recursos, saída de previsão. Cada passo está errado.
A série temporal quebra as suposições nas quais o ML padrão se baseia. As amostras não são independentes – a temperatura de hoje depende da de ontem. As divisões aleatórias vazam informações futuras para o passado. Recursos que parecem ótimos no backtest falham na produção porque dependem de padrões que mudam com o tempo.
Um modelo que obtém 95% de precisão com validação cruzada aleatória pode obter 55% com avaliação adequada baseada no tempo. A diferença não é um detalhe técnico. É a diferença entre um modelo que funciona no papel e outro que funciona na produção.
Esta lição aborda os fundamentos: o que torna os dados de tempo diferentes, como avaliar modelos honestamente e como transformar uma série temporal em recursos que os modelos de ML padrão podem consumir.
O Conceito
O que torna as séries temporais diferentes
O ML padrão assume i.i.d. - independente e distribuído de forma idêntica. Cada amostra é extraída da mesma distribuição, independentemente de outras amostras. A série temporal viola ambos:
- Não independente. O preço das ações de hoje depende do de ontem. As vendas desta semana estão correlacionadas com as da semana passada.
- Não distribuído de forma idêntica. A distribuição muda com o tempo. As vendas em dezembro parecem diferentes das vendas em março.
Essas violações não são menores. Eles mudam a forma como você cria recursos, como avalia modelos e quais algoritmos funcionam.
flowchart LR
subgraph IID["Standard ML (i.i.d.)"]
direction TB
S1[Sample 1] ~~~ S2[Sample 2]
S2 ~~~ S3[Sample 3]
end
subgraph TS["Time Series (not i.i.d.)"]
direction LR
T1[t=1] --> T2[t=2]
T2 --> T3[t=3]
T3 --> T4[t=4]
end
style S1 fill:#dfd
style S2 fill:#dfd
style S3 fill:#dfd
style T1 fill:#ffd
style T2 fill:#ffd
style T3 fill:#ffd
style T4 fill:#ffd
No ML padrão, as amostras são intercambiáveis. Embaralhá-los não muda nada. Nas séries temporais, a ordem é tudo. O embaralhamento destrói o sinal.
Componentes de uma série temporal
Cada série temporal é uma combinação de:
flowchart TD
A[Observed Time Series] --> B[Trend]
A --> C[Seasonality]
A --> D[Residual/Noise]
B --> E[Long-term direction: up, down, flat]
C --> F[Repeating patterns: daily, weekly, yearly]
D --> G[Random variation after removing trend and seasonality]
- Tendência: A direção de longo prazo. Faturamento crescendo 10% ao ano. Aumento da temperatura global.
- Sazonalidade: Repetição de padrões em intervalos fixos. As vendas no varejo disparam em dezembro. O uso do ar condicionado atinge o pico em julho.
- Residual: o que resta após a remoção da tendência e da sazonalidade. Se o resíduo parecer ruído branco, a decomposição capturou o sinal.
Estacionaridade
Uma série temporal é estacionária se suas propriedades estatísticas (média, variância, autocorrelação) não mudam ao longo do tempo. A maioria dos métodos de previsão assume estacionariedade.
Por que é importante: Uma série não estacionária tem uma média que varia. Um modelo treinado com dados de janeiro aprendeu uma média diferente daquela mostrada em fevereiro. Será sistematicamente errado.
Como verificar: Calcule a média móvel e o desvio padrão móvel nas janelas. Se eles derivarem, a série não será estacionária.
Como corrigir: Diferenciação. Em vez de modelar os valores brutos, modele a mudança entre valores consecutivos:
diff[t] = value[t] - value[t-1]
Se uma rodada de diferenciação não tornar a série estacionária, aplique-a novamente (diferenciação de segunda ordem). A maioria das séries do mundo real precisa de no máximo duas rodadas.
Exemplo:
Série original: [100, 102, 106, 112, 120] Primeira diferença: [2, 4, 6, 8] (ainda com tendência de alta) Segunda diferença: [2, 2, 2] (constante - estacionário)
A série original apresentava tendência quadrática. A primeira diferenciação transformou-a em uma tendência linear. A segunda diferença tornou-o plano. Na prática, raramente são necessárias mais de duas rodadas.
Teste formal: O teste Augmented Dickey-Fuller (ADF) é o teste estatístico padrão para estacionariedade. A hipótese nula é “a série é não estacionária”. Um valor p abaixo de 0,05 significa que você pode rejeitar o nulo e concluir a estacionariedade. Não implementamos ADF do zero (requer tabelas de distribuição assintóticas), mas a abordagem de estatísticas contínuas em nosso código fornece uma verificação visual prática.
Autocorrelação
A autocorrelação mede o quanto um valor no tempo t se correlaciona com o valor no tempo tk (k passos no passado). A função de autocorrelação (ACF) traça essa correlação para cada defasagem k.
ACF diz a você:
- Há quanto tempo a série se lembra. Se o ACF cair para zero após o intervalo 5, os valores anteriores a 5 passos serão irrelevantes.
- Se existe sazonalidade. Se o ACF aumentar na defasagem 12 (dados mensais), há sazonalidade anual.
- Quantos recursos de atraso criar. Use atrasos até onde o ACF se torna insignificante.
PACF (função de autocorrelação parcial) remove correlações indiretas. Se hoje se correlacionar com 3 dias atrás apenas porque ambos se correlacionam com ontem, o PACF no atraso 3 será zero, enquanto o ACF no atraso 3 não será.
Recursos de atraso: transformando séries temporais em aprendizagem supervisionada
Os modelos de ML padrão precisam de uma matriz de recursos X e um alvo y. A série temporal fornece uma única coluna de valores. A ponte tem recursos de atraso.
Pegue a série [10, 12, 14, 13, 15] e crie recursos lag-1 e lag-2:
| atraso_2 | atraso_1 | alvo |
|---|---|---|
| 10 | 12 | 14 |
| 12 | 14 | 13 |
| 14 | 13 | 15 |
Agora você tem um problema de regressão padrão. Qualquer modelo de ML (regressão linear, random forest, aumento de gradiente) pode prever o alvo a partir das defasagens.
Recursos adicionais que você pode projetar:
- Estatísticas contínuas: média, padrão, mínimo, máximo nos últimos k valores
- Recursos do calendário: dia da semana, mês, é_feriado, é_fim de semana
- Valores diferenciados: alteração da etapa anterior
- Estatísticas de expansão: média cumulativa, soma cumulativa
- Recursos de proporção: valor atual/média móvel (a que distância da média recente)
- Recursos de interação: lag_1 * day_of_week (efeitos dos dias da semana no impulso)
Quantos atrasos? Use a função de autocorrelação. Se o ACF for significativo até o atraso 10, use pelo menos 10 atrasos. Se houver sazonalidade semanal, inclua o atraso 7 (e possivelmente 14). Mais defasagens dão ao modelo mais histórico, mas também mais recursos para ajustar, aumentando o risco de overfitting.
A armadilha de alinhamento de destino. Ao criar recursos de atraso, o destino deve ser o valor no tempo t e todos os recursos devem usar valores no tempo t-1 ou anterior. Se você incluir acidentalmente o valor no tempo t como um recurso, terá um preditor perfeito – e um modelo completamente inútil. Este é o bug mais comum na engenharia de características de série temporal.
Validação passo a passo
Este é o conceito mais importante desta lição. A validação cruzada k-fold padrão atribui amostras aleatoriamente para treinar e testar. Para séries temporais, isso vaza informações futuras.
flowchart TD
subgraph WRONG["Random Split (WRONG)"]
direction LR
W1[Jan] --> W2[Mar]
W2 --> W3[Feb]
W3 --> W4[May]
W4 --> W5[Apr]
style W1 fill:#fdd
style W3 fill:#fdd
style W5 fill:#fdd
style W2 fill:#dfd
style W4 fill:#dfd
end
subgraph RIGHT["Walk-Forward (CORRECT)"]
direction LR
R1["Train: Jan-Mar"] --> R2["Test: Apr"]
R3["Train: Jan-Apr"] --> R4["Test: May"]
R5["Train: Jan-May"] --> R6["Test: Jun"]
style R1 fill:#dfd
style R2 fill:#fdd
style R3 fill:#dfd
style R4 fill:#fdd
style R5 fill:#dfd
style R6 fill:#fdd
end
Validação passo a passo:
- Treine com dados até o momento t
- Prever no tempo t+1 (ou t+1 a t+k para múltiplas etapas)
- Deslize a janela para frente
- Repita
Cada dobra de teste contém apenas os dados que vêm depois de todos os dados de treinamento. Nenhum vazamento futuro. Isso fornece uma estimativa honesta do desempenho do modelo quando implantado.
A janela em expansão usa todos os dados históricos para treinamento (a janela aumenta). Janela deslizante usa uma janela de treinamento de tamanho fixo (janela de slides). Use a expansão quando acreditar que os dados mais antigos ainda são relevantes. Use o deslizamento quando o mundo mudar e os dados antigos prejudicarem.
Intuição ARIMA
ARIMA é o modelo clássico de série temporal. Possui três componentes:
- AR (Autoregressivo): Prever a partir de valores anteriores. AR(p) usa os últimos valores de p.
- I (Integrado): Diferenciação para alcançar estacionariedade. I(d) aplica d rodadas de diferenciação.
- MA (Média Móvel): Prever a partir de erros de previsão anteriores. MA(q) usa os últimos q erros.
ARIMA(p, d, q) combina todos os três. Você escolhe p, d, q com base na análise ACF/PACF ou pesquisa automatizada (auto-ARIMA).
Não implementaremos o ARIMA do zero – ele requer otimização numérica que está além do escopo desta lição. O principal insight é entender o que cada componente faz para que você possa interpretar os resultados do ARIMA e saber quando usá-lo.
Quando usar o quê
| Abordagem | Melhor para | Lida com a sazonalidade | Lida com recursos externos |
|---|---|---|---|
| Recursos de atraso + ML | Tabular com muitos recursos externos | Com recursos de calendário | Sim |
| ARIMA | Série univariada única, curto prazo | Variante SARIMA | Não (ARIMAX para limitado) |
| Suavização exponencial | Tendência simples + sazonalidade | Sim (Holt-Winters) | Não |
| Profeta | Previsão de negócios, feriados | Sim (termos de Fourier) | Limitado |
| Redes Neurais (LSTM, Transformer) | Sequências longas, muitas séries | Aprendido | Sim |
Para a maioria dos problemas práticos, recursos de atraso + aumento de gradiente são o ponto de partida mais forte. Ele lida com recursos externos naturalmente, não requer estacionariedade e é fácil de depurar.
Previsão de Horizontes e Estratégias
A previsão de etapa única prevê um passo à frente. A previsão em várias etapas prevê várias etapas. Existem três estratégias:
Recursivo (iterado): Preveja um passo à frente, use a previsão como entrada para o próximo passo. Simples, mas os erros se acumulam – cada previsão usa a previsão anterior, então os erros se acumulam.
Direto: treine um modelo separado para cada horizonte. O Modelo 1 prevê t+1, o Modelo 5 prevê t+5. Não há acúmulo de erros, mas cada modelo possui menos amostras de treinamento e não compartilha informações.
Múltiplas saídas: Treine um modelo que produza todos os horizontes simultaneamente. Compartilha informações entre horizontes, mas requer um modelo que suporte múltiplas saídas (ou uma função de perda personalizada).
Para a maioria dos problemas práticos, comece com recursivo para horizontes curtos (1-5 passos) e direto para horizontes mais longos.
Erros comuns em séries temporais
| Erro | Por que isso acontece | Como consertar |
|---|---|---|
| Divisão aleatória de treino/teste | Hábito do ML padrão | Use avanço ou divisão temporal |
| Usando recursos futuros | Recurso no momento t incluído por engano | Audite cada recurso para alinhamento temporal |
| Overfitting à sazonalidade | Modelo memoriza padrões de calendário | Realizar um ciclo sazonal completo no conjunto de testes |
| Ignorando mudanças de escala | Receita duplica mas padrões permanecem | Alteração percentual do modelo em vez de absoluta |
| Muitos recursos de atraso | “Mais história é melhor” | Use ACF para determinar defasagens relevantes |
| Não diferenciando | “A modelo vai descobrir” | Os modelos de árvore lidam com tendências; modelos lineares precisam de estacionariedade |
Construa
O código em code/time_series.py implementa os blocos de construção principais do zero.
Criador de recursos de atraso
def make_lag_features(series, n_lags):
n = len(series)
X = np.full((n, n_lags), np.nan)
for lag in range(1, n_lags + 1):
X[lag:, lag - 1] = series[:-lag]
valid = ~np.isnan(X).any(axis=1)
return X[valid], series[valid]
Isso converte uma série 1D em uma matriz de recursos onde cada linha tem os últimos valores n_lags como recursos e o valor atual como destino.
Validação cruzada passo a passo
def walk_forward_split(n_samples, n_splits=5, min_train=50):
assert min_train < n_samples, "min_train must be less than n_samples"
step = max(1, (n_samples - min_train) // n_splits)
for i in range(n_splits):
train_end = min_train + i * step
test_end = min(train_end + step, n_samples)
if train_end >= n_samples:
break
yield slice(0, train_end), slice(train_end, test_end)
Cada divisão garante que os dados de treinamento cheguem estritamente antes dos dados de teste. A janela de treinamento se expande a cada dobra.
Modelo Autoregressivo Simples
Um modelo AR puro é apenas uma regressão linear em recursos de atraso:
class SimpleAR:
def __init__(self, n_lags=5):
self.n_lags = n_lags
self.weights = None
self.bias = None
def fit(self, series):
X, y = make_lag_features(series, self.n_lags)
# Solve via normal equations
X_b = np.column_stack([np.ones(len(X)), X])
theta = np.linalg.lstsq(X_b, y, rcond=None)[0]
self.bias = theta[0]
self.weights = theta[1:]
return self
Isto é conceitualmente idêntico à regressão linear da Lição 02, mas aplicado a versões defasadas no tempo da mesma variável.
Verificação de estacionariedade
O código calcula estatísticas contínuas para avaliar visual e numericamente a estacionariedade:
def check_stationarity(series, window=50):
rolling_mean = np.array([
series[max(0, i - window):i].mean()
for i in range(1, len(series) + 1)
])
rolling_std = np.array([
series[max(0, i - window):i].std()
for i in range(1, len(series) + 1)
])
return rolling_mean, rolling_std
Se a média móvel oscila ou o padrão móvel muda, a série é não estacionária. Aplique a diferenciação e verifique novamente.
O código também verifica a estacionariedade comparando a primeira e a segunda metade da série. Se as médias diferirem em mais de meio desvio padrão ou a razão de variância exceder 2x, a série será marcada como não estacionária.
Autocorrelação
def autocorrelation(series, max_lag=20):
n = len(series)
mean = series.mean()
var = series.var()
acf = np.zeros(max_lag + 1)
for k in range(max_lag + 1):
cov = np.mean((series[:n-k] - mean) * (series[k:] - mean))
acf[k] = cov / var if var > 0 else 0
return acf
Use-o
Com o sklearn, você usa recursos de atraso diretamente com qualquer regressor:
from sklearn.linear_model import Ridge
from sklearn.ensemble import GradientBoostingRegressor
X, y = make_lag_features(series, n_lags=10)
for train_idx, test_idx in walk_forward_split(len(X)):
model = Ridge(alpha=1.0)
model.fit(X[train_idx], y[train_idx])
predictions = model.predict(X[test_idx])
Para ARIMA, use modelos de estatísticas:
from statsmodels.tsa.arima.model import ARIMA
model = ARIMA(train_series, order=(5, 1, 2))
fitted = model.fit()
forecast = fitted.forecast(steps=30)
O código em time_series.py demonstra ambas as abordagens e as compara usando validação passo a passo.
sklearn TimeSeriesSplit
sklearn fornece TimeSeriesSplit que implementa validação passo a passo:
from sklearn.model_selection import TimeSeriesSplit
tscv = TimeSeriesSplit(n_splits=5)
for train_index, test_index in tscv.split(X):
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
model.fit(X_train, y_train)
score = model.score(X_test, y_test)
Isso é equivalente ao nosso walk_forward_split inicial, mas integrado à estrutura de validação cruzada do sklearn. Você pode usá-lo com cross_val_score:
from sklearn.model_selection import cross_val_score
scores = cross_val_score(model, X, y, cv=TimeSeriesSplit(n_splits=5))
print(f"Mean score: {scores.mean():.4f} +/- {scores.std():.4f}")
Métricas de avaliação
A previsão de série temporal usa métricas de regressão, mas com contexto ciente do tempo:
- MAE (Erro Médio Absoluto): Média de |y_true - y_pred|. Fácil de interpretar em unidades originais. "Em média, as previsões estão erradas em 3,2 graus."
- RMSE (Root Mean Squared Error): Raiz quadrada do erro quadrático médio. Penaliza mais erros grandes que o MAE. Use quando erros grandes são piores do que muitos erros pequenos.
- MAPE (Erro Percentual Médio Absoluto): Média de |erro / true_value| * 100. Independente de escala, útil para comparação entre séries diferentes. Mas indefinido quando os valores verdadeiros são zero.
- Comparação de linha de base ingênua: Sempre compare com linhas de base simples. A linha de base ingênua sazonal prevê o valor de um período atrás (ontem, semana passada). Se o seu modelo não consegue vencer o ingênuo, algo está errado.
Recursos rolantes
O código demonstra a adição de estatísticas contínuas (média, padrão, mínimo, máximo em janelas de 7 e 14 dias) aos recursos de atraso. Eles fornecem ao modelo informações sobre tendências recentes e volatilidade que os recursos de defasagem por si só não capturam.
Por exemplo, se a média móvel estiver subindo, isso sugere uma tendência ascendente. Se o padrão móvel estiver aumentando, isso sugere volatilidade crescente. Esses são os tipos de padrões com os quais os modelos baseados em árvore podem aprender, mas os modelos lineares não.
Envie
Esta lição produz:
outputs/prompt-time-series-advisor.md- um prompt para enquadrar problemas de série temporalcode/time_series.py-- recursos de atraso, validação walk-forward, modelo AR, verificações de estacionariedade
Linhas de base que você deve superar
Antes de construir qualquer modelo, estabeleça linhas de base:
- Último valor (persistência). Preveja que amanhã será igual a hoje. Para muitas séries, isso é surpreendentemente difícil de vencer.
- Ingênuo sazonal. Preveja que hoje será igual ao mesmo dia da semana passada (ou do ano passado). Se o seu modelo não consegue superar isso, ele não aprendeu nenhum padrão útil além da sazonalidade.
- Média móvel. Preveja a média dos últimos k valores. Suaviza o ruído, mas não consegue capturar mudanças repentinas.
Se o seu modelo sofisticado de ML perder para a linha de base ingênua sazonal, você tem um bug. Mais comumente: vazamento futuro de recursos, método de avaliação incorreto ou a série é verdadeiramente aleatória e imprevisível.
Dicas Práticas
Comece com a plotagem. Antes de qualquer modelagem, plote a série bruta. Procure tendências, sazonalidade, valores discrepantes, quebras estruturais (mudanças repentinas de comportamento). Uma inspeção visual de 30 segundos geralmente indica mais de uma hora de análise automatizada.
Diferença primeiro, modelo depois. Se a série tiver uma tendência clara, diferencie-a antes de criar recursos de atraso. Os modelos baseados em árvore podem lidar com tendências, mas os modelos lineares não, e a diferenciação nunca é demais.
Realize pelo menos um ciclo sazonal completo. Se você tiver sazonalidade semanal, seu conjunto de testes precisará de pelo menos uma semana inteira. Se mensalmente, pelo menos um mês completo. Caso contrário, não será possível avaliar se o modelo capturou o padrão sazonal.
Monitore a produção. Os modelos de série temporal se degradam com o tempo, à medida que o mundo muda. Rastreie erros de previsão continuamente. Quando os erros começarem a aumentar, treine novamente o modelo com base em dados recentes.
Cuidado com mudanças de regime. Um modelo treinado em dados pré-pandemia não irá prever o comportamento pós-pandemia. Inclua indicadores de mudanças de regime conhecidas como recursos ou use uma janela deslizante que esqueça dados antigos.
Séries distorcidas por transformação logarítmica. Receitas, preços e contagens são frequentemente distorcidos à direita. Tomar o log estabiliza a variância e torna os padrões multiplicativos aditivos, com os quais os modelos lineares podem lidar. Preveja no espaço logarítmico e, em seguida, exponencie para voltar às unidades originais.
Exercícios
Experimento de estacionariedade. Gere uma série com tendência linear. Verifique a estacionariedade com estatísticas contínuas. Aplique a primeira diferenciação. Verifique novamente. Quantas rodadas de diferenciação são necessárias para uma tendência quadrática?
Seleção de atraso. Calcular ACF em uma série sazonal (período=7). Quais defasagens têm a maior autocorrelação? Crie recursos de atraso usando apenas esses atrasos (não atrasos consecutivos). A precisão melhora em comparação com o uso dos atrasos de 1 a 7?
Avanço versus divisão aleatória. Treine uma regressão Ridge em recursos de atraso. Avalie com divisão aleatória 80/20 e com validação walk-forward. Quanto a divisão aleatória superestima o desempenho?
Engenharia de características. Adicione média contínua (janela = 7), padrão contínuo (janela = 7) e recursos de dia da semana aos recursos de atraso. Compare a precisão com e sem esses extras usando a validação passo a passo.
Previsão em várias etapas. Modifique o modelo AR para prever 5 etapas à frente em vez de 1. Compare duas estratégias: (a) prever uma etapa, usar a previsão como entrada para a próxima etapa (recursiva) e (b) treinar modelos separados para cada horizonte (direto). Qual é mais preciso?
Termos-chave
| Prazo | O que as pessoas dizem | O que isso realmente significa |
|---|---|---|
| Estacionaridade | “As estatísticas não mudam com o tempo” | Uma série cuja média, variância e estrutura de autocorrelação são constantes ao longo do tempo |
| Diferenciando | "Subtrair valores consecutivos" | Calculando y[t] - y[t-1] para remover tendências e alcançar estacionariedade |
| Autocorrelação (ACF) | “Como uma série se correlaciona consigo mesma” | A correlação entre uma série temporal e uma cópia desfasada dela mesma, em função do desfasamento |
| Autocorrelação parcial (PACF) | "Somente correlação direta" | Autocorrelação no desfasamento k após remoção do efeito de todos os desfasamentos mais curtos |
| Recursos de atraso | "Valores passados como entradas" | Usando y[t-1], y[t-2], ..., y[t-k] como recursos para prever y[t] |
| Validação passo a passo | "Validação cruzada que respeita o tempo" | Avaliação onde os dados de treinamento sempre precedem cronologicamente os dados de teste |
| ARIMA | “O modelo clássico de série temporal” | Média móvel integrada autoregressiva: combina valores passados (AR), diferenciais (I) e erros passados (MA) |
| Sazonalidade | "Repetindo padrões de calendário" | Ciclos regulares e previsíveis numa série temporal ligada a períodos de calendário (diário, semanal, anual) |
| Tendência | “A direção de longo prazo” | Aumento ou diminuição persistente do nível da série ao longo do tempo |
| Janela em expansão | "Usar todo o histórico" | Validação passo a passo onde o conjunto de treinamento cresce a cada dobra |
| Janela deslizante | "Histórico de tamanho fixo" | Validação walk-forward onde o conjunto de treinamento é uma janela de comprimento fixo que desliza para frente |
Leitura Adicional
- Hyndman e Athanasopoulos, Forecasting: Principles and Practice (3ª ed.) - o melhor livro gratuito sobre previsão de séries temporais
- scikit-learn Divisão de série temporal - divisor walk-forward do sklearn
- statsmodels ARIMA docs -- Implementação ARIMA com diagnóstico
- Makridakis et al., The M5 Competition (2022) - competição de previsão em grande escala mostrando métodos de ML versus métodos estatísticos