Validação cruzada para séries temporais
O que “Validação Cruzada de Séries Temporais” Significa (e Por Que É Diferente)
No aprendizado de máquina (machine learning) i.i.d. padrão, a validação cruzada (CV) estima o erro de generalização ao dividir aleatoriamente os exemplos em dobras (folds) de treino/validação. Séries temporais violam a suposição i.i.d. porque as observações são temporalmente dependentes e frequentemente não estacionárias. Embaralhar aleatoriamente normalmente causa vazamento de informação (information leakage): o modelo “vê o futuro” durante o treinamento e obtém uma pontuação de validação irrealisticamente otimista.
A validação cruzada de séries temporais (frequentemente chamada de retroteste (backtesting)) substitui dobras aleatórias por divisões que respeitam o tempo que imitam como o modelo será treinado e usado em produção.
Este artigo se apoia em ideias gerais de Validação & Validação Cruzada e complementa Divisão Treino-Teste ao focar em dados dependentes do tempo.
Vazamento em Séries Temporais: O Que Dá Errado
O vazamento pode ser óbvio (treinar com dados do futuro) ou sutil (engenharia de atributos e pré-processamento que usam informações futuras). Fontes comuns de vazamento:
- Divisões k-fold aleatórias: o treinamento contém timestamps posteriores ao da validação.
- Atributos de janela móvel calculados no conjunto completo: por exemplo, calcular uma média móvel com janela centralizada, ou usar valores futuros na suavização.
- Normalização/imputação global: ajustar um escalonador/imputador em todos os dados antes de dividir.
- Janelas de rótulos sobrepostas: para previsão multi-passos, alvos de dobras adjacentes podem se sobrepor, permitindo que o treinamento “toque” indiretamente a validação.
- Revisões/backfill: em muitos domínios (finanças, epidemiologia), valores históricos são revisados; usar valores revisados para timestamps anteriores é uma forma de vazamento por retrospectiva.
A regra central é:
Todas as transformações e o ajuste do modelo devem usar apenas informações disponíveis até o tempo de corte do treinamento.
Na prática, isso significa usar pipelines ajustados separadamente dentro de cada dobra.
Enquadramento de Implantação: O Que Você Está Simulando?
Antes de escolher um esquema de CV, esclareça o ciclo de implantação:
- Horizonte de previsão: quão à frente você prevê? (por exemplo, 1 dia à frente, 7 dias à frente, 24 horas à frente)
- Frequência de atualização: você re-treina diariamente/semanalmente, ou apenas ocasionalmente?
- Frequência de predição: você prevê a cada hora/dia, ou apenas em fronteiras de período?
- Disponibilidade de atributos:
- Covariáveis futuras são conhecidas? (por exemplo, efeitos de calendário, mudanças de preço planejadas)
- Elas são apenas parcialmente conhecidas? (por exemplo, previsões do tempo)
- Restrições de latência: você consegue calcular atributos e re-treinar a tempo?
É melhor pensar em CV para séries temporais como uma simulação offline do processo de produção.
Estratégias Principais de Divisão
CV com Janela Expansiva (Crescente)
Ideia: Treinar com todos os dados até o tempo (t), validar no próximo período.
- Janela de treinamento: ([1, \dots, t])
- Janela de validação: ([t+1, \dots, t+h])
Isso corresponde a muitos fluxos de trabalho reais em que você continua acumulando histórico.
Prós
- Usa o máximo de dados conforme o tempo avança (bom quando os dados são escassos).
- Imita o re-treinamento “aprender com tudo até aqui”.
Contras
- Se o processo muda ao longo do tempo (deriva de conceito (concept drift)), dados muito antigos podem atrapalhar.
Exemplo (janela expansiva, horizonte = 7 dias):
Dobra 1: treina dias 1–90 → valida dias 91–97
Dobra 2: treina dias 1–97 → valida dias 98–104
…
CV com Janela Móvel (Deslizante)
Ideia: Treinar em uma janela recente de comprimento fixo, validar no próximo período.
- Janela de treinamento: ([t-w+1, \dots, t])
- Janela de validação: ([t+1, \dots, t+h])
Prós
- Adapta-se melhor sob deriva (foca no histórico recente).
- Custo computacional fixo por dobra.
Contras
- Descarta dados antigos que podem conter padrões sazonais valiosos ou eventos raros.
Quando é útil
- Previsão de demanda com comportamento em mudança
- Métricas de atividade de usuários com mudanças de produto
- Sinais de negociação de alta frequência
Validação com Origem Deslizante / Walk-Forward (Backtesting)
“Validação walk-forward” geralmente se refere a mover repetidamente a origem da previsão para frente e avaliar no próximo horizonte. Na prática, é um termo guarda-chuva que cobre janelas de treinamento expansivas ou móveis com avaliação sequencial.
Use validação walk-forward quando você quer simular:
- re-treinamento periódico (diário/semanal)
- geração de previsões repetidamente ao longo do tempo
- monitoramento de degradação entre regimes
Ela responde: “Como este modelo teria se saído se o tivéssemos implantado mais cedo e continuado a executá-lo?”
Validação Cruzada em Blocos (K-Fold em Blocos)
Ideia: Dividir o eixo do tempo em (K) blocos contíguos; usar alguns blocos para treinamento e outro para validação, mantendo a ordem.
Uma versão simples:
- Particionar em blocos: B1, B2, …, BK
- Para a dobra i: treinar nos blocos antes de Bi, validar em Bi
Isso se assemelha à janela expansiva, mas com “pedaços” mais grosseiros (por exemplo, meses/trimestres). Outra variante é k-fold em blocos com lacunas (ver abaixo), em que você deixa um espaço entre os blocos de treino e validação.
Prós
- Simples e interpretável.
- Útil quando você quer dobras alinhadas a períodos de negócio significativos.
Contras
- Ainda pode vazar se os atributos usarem janelas que cruzam a fronteira (a menos que você adicione uma lacuna).
- Menos granular do que a avaliação walk-forward.
A “Lacuna” (Embargo): Evitando Vazamento na Fronteira
Mesmo com divisões que respeitam o tempo, pode haver vazamento por causa de proximidade temporal:
- Você calcula atributos usando janelas que se estendem além da fronteira da divisão.
- Rótulos se sobrepõem entre dobras (especialmente em cenários multi-passos).
- A correlação serial torna a validação “fácil demais” se o treinamento termina imediatamente antes da validação.
Uma lacuna (também chamada de embargo no mercado financeiro) impõe um amortecedor entre treinamento e validação:
- Treinamento: até o tempo (t)
- Lacuna: ((t, t+g])
- Validação: ([t+g+1, t+g+h])
Escolha a lacuna para cobrir:
- o lookback máximo usado nos atributos (por exemplo, 30 dias para uma média móvel de 30 dias), e/ou
- o período em que os rótulos se sobrepõem, e/ou
- um “cooldown” operacional para reduzir dependência
Regra prática:
Defina gap >= max_feature_lookback se você usa atributos de janela móvel/defasagem que, caso contrário, poderiam incorporar informação da validação.
Horizonte de Previsão e Avaliação Multi-Passos
Previsão de Um Passo vs Multi-Passos
- Um passo à frente: prever (y_{t+1}) usando dados até (t)
- Multi-passos à frente: prever (y_{t+h}) (ou todo um caminho (y_{t+1:t+h}))
A previsão multi-passos introduz escolhas:
- Direta: treinar modelos separados por horizonte (h)
- Recursiva: realimentar as previsões como entradas
- Multi-saída: prever todo o horizonte de uma vez
Sua CV deve corresponder ao método:
- Se sua implantação prevê 7 dias à frente como um vetor, valide em blocos de 7 dias.
- Se você se importa com qualidade específica por horizonte (dia+1 vs dia+7), compute métricas por horizonte.
Alvos de Previsão Sobrepostos
Se você gera uma previsão todos os dias com um horizonte de 7 dias, os alvos de validação se sobrepõem fortemente. Isso é realista em produção, mas complica a independência estatística. Ainda é aceitável — apenas interprete intervalos de confiança com cuidado e prefira agregação em blocos dos erros (por exemplo, médias mensais) ao fazer testes de significância (ver Desenho de Experimentos & Poder).
Múltiplas Sazonalidades: Como as Divisões Podem Enganar
Muitas séries reais têm múltiplos padrões sazonais:
- dados horários: sazonalidade diária + semanal
- varejo: semanal + anual + efeitos de feriados
- energia: diária + semanal + ciclos guiados por clima
Se sua janela de treinamento não inclui ciclos suficientes, o modelo pode parecer pior (ou melhor) do que realmente é.
Diretrizes práticas:
- Garanta que a janela de treinamento abranja pelo menos 2–3 ciclos completos da sazonalidade importante mais lenta (frequentemente anual).
- Garanta que a validação cubra períodos representativos (por exemplo, inclua feriados se forem relevantes).
- Considere estratificar ao longo do tempo escolhendo blocos de validação que cubram diferentes estações (por exemplo, validar em vários meses ao longo do ano), mas ainda em ordem cronológica.
Exemplo: Para sazonalidade semanal + anual, uma janela móvel de 6 semanas provavelmente sub-representará padrões anuais; use uma janela mais longa ou inclua atributos de calendário.
Escolhendo uma Estratégia de CV: Um Guia Prático de Decisão
Use janela expansiva quando…
- o processo é relativamente estável
- mais dados geralmente ajudam
- você espera que padrões sazonais longos importem (anuais)
- o re-treinamento em produção usa todo o histórico
Use janela móvel quando…
- a deriva de conceito é significativa
- dados antigos são enganosos (mudanças de produto, mudanças de política)
- você tem dados de alta frequência em que histórico longo é desnecessário
- restrições de computação favorecem tamanho de treino fixo
Use CV em blocos quando…
- você quer dobras alinhadas a períodos de negócio (meses/trimestres)
- você precisa de menos dobras para modelos caros
- você está fazendo seleção de modelo com granularidade temporal grosseira
Use validação walk-forward quando…
- você quer a simulação mais realista de previsões e re-treinamentos repetidos
- você precisa entender o desempenho ao longo do tempo, não apenas o desempenho médio
- você planeja monitorar e atualizar o modelo regularmente
Padrões Práticos de Implementação (com Exemplos)
Exemplo 1: Divisões walk-forward em Python (custom)
Below is a simple generator for rolling-origin evaluation with optional rolling/expanding training and a gap.
import numpy as np
def time_series_splits(n, train_size, val_size, step, gap=0, expanding=False):
"""
n: number of time points (assume ordered)
train_size: initial train length (for expanding, it's the minimum)
val_size: validation length (horizon block)
step: how far to move the origin each fold
gap: embargo between train end and val start
expanding: if True, train start stays at 0; else rolling window
"""
start = 0
train_start = 0
while True:
train_end = start + train_size
val_start = train_end + gap
val_end = val_start + val_size
if val_end > n:
break
if expanding:
train_idx = np.arange(0, train_end)
else:
train_idx = np.arange(train_start, train_end)
val_idx = np.arange(val_start, val_end)
yield train_idx, val_idx
start += step
if not expanding:
train_start += step
Exemplo de uso:
- dados diários
- treinar nos últimos 180 dias
- validar nos próximos 14 dias
- avançar 14 dias por dobra (validações não sobrepostas)
- lacuna de 7 dias para proteger contra vazamento de atributos de média móvel de 7 dias
splits = list(time_series_splits(
n=1000, train_size=180, val_size=14, step=14, gap=7, expanding=False
))
print(len(splits), "folds")
Exemplo 2: scikit-learn `TimeSeriesSplit` (e suas limitações)
O TimeSeriesSplit do scikit-learn fornece divisões com janela expansiva, mas historicamente teve suporte limitado para lacunas dependendo da versão. Ele também não entende horizontes de previsão diretamente; você ainda precisa estruturar seu conjunto de dados de aprendizado supervisionado corretamente (defasagens, alvos, etc.) e garantir que sua validação corresponda ao horizonte desejado.
Se você construir uma matriz de atributos em que cada linha corresponde ao tempo (t) e o rótulo é (y_{t+h}), você deve garantir:
- linhas de treinamento usam apenas informações até seu tempo (t)
- linhas de validação correspondem a tempos posteriores
- você aplica uma lacuna se suas janelas de atributos puderem cruzar fronteiras
Disciplina de pipeline: ajustar transformações por dobra
Se você usar escalonamento, imputação, PCA ou qualquer pré-processamento aprendido, use um pipeline e ajuste-o dentro de cada dobra:
- Ajustar o pipeline apenas no subconjunto de treinamento
- Transformar treinamento e validação separadamente
- Treinar o modelo no treinamento transformado
- Avaliar na validação transformada
Este é o mesmo princípio de Validação & Validação Cruzada, mas séries temporais tornam violações mais comuns porque atributos de janela móvel frequentemente são calculados “globalmente” por engano.
Avaliando sob Restrições Realistas
Métricas pontuais vs métricas probabilísticas
Para previsões pontuais, métricas comuns incluem MAE, RMSE, MAPE/sMAPE e MASE. Escolha com base na sua preferência de perda e em questões de escala (ver Métricas).
Para previsões probabilísticas (quantis ou distribuições completas), prefira regras de pontuação próprias (proper scoring rules):
- perda pinball para quantis
- CRPS (continuous ranked probability score)
- log score (para modelos de verossimilhança completa)
Se você produzir intervalos de previsão, avalie:
- cobertura (com que frequência o valor verdadeiro cai dentro)
- nitidez (sharpness) (quão estreitos são os intervalos)
Para avaliação de intervalos/probabilística e conceitos de calibração, veja Quantificação de Incerteza e Calibração. Para intervalos livres de distribuição em séries temporais com desenho cuidadoso de divisões, veja Predição Conformal.
Alinhe a avaliação à cadência de re-treinamento
Se a produção re-treina semanalmente, não avalie como se você re-treinasse antes de cada previsão. A avaliação walk-forward deve simular:
- treinar no tempo (t)
- gerar previsões para o próximo horizonte
- avançar o tempo para o próximo momento de re-treino
- repetir
Isso pode mudar materialmente os resultados, especialmente sob deriva.
Lide com covariáveis “futuras conhecidas” vs “futuras desconhecidas”
Variáveis exógenas (promoções, feriados, clima, preços) frequentemente determinam o desempenho. Na CV, você deve respeitar o que é conhecido no momento da previsão:
- Atributos de calendário (dia da semana, mês, indicadores de feriado): normalmente conhecidos com antecedência → OK usar na validação.
- Promoções/preços planejados: podem ser conhecidos → OK se realmente estiverem agendados.
- Clima: valores futuros não são conhecidos; no melhor caso você tem previsões → ou
- exclua atributos de clima futuro, ou
- substitua-os por previsões do tempo (e valide usando a previsão que você teria naquela época).
Falhar em modelar a disponibilidade de covariáveis é uma grande causa de “vitórias offline, perdas online”.
Simule revisões de dados (backfill)
Se seu pipeline de dados revisa o histórico (eventos que chegam atrasados, medições corrigidas), então treinar com o histórico final “limpo” é irrealista. A avaliação padrão-ouro usa conjuntos de dados de snapshot: o que você teria sabido naquele momento.
Se snapshots não estiverem disponíveis, seja explícito sobre a limitação e considere lacunas conservadoras e verificações de robustez.
Agregando Resultados ao Longo das Dobras
A CV de séries temporais produz uma distribuição de pontuações por dobra. Não reporte apenas a média:
- reporte média + variabilidade (desvio padrão/quantis)
- plote desempenho ao longo do tempo (erro vs data final da dobra)
- analise falhas por regime/estação (ver Análise de Erros (Fatiamento))
Um modelo com erro médio ligeiramente pior, mas com erro de pior caso muito menor, pode ser preferível operacionalmente.
Checklist de Armadilhas Comuns
- Embaralhar o tempo em qualquer ponto do pipeline.
- Calcular atributos no conjunto completo antes de dividir (defasagens/estatísticas de janela móvel devem ser seguras por dobra).
- Sem lacuna/embargo apesar de janelas de lookback longas ou rótulos sobrepostos.
- Avaliar em um horizonte mais fácil do que em produção (por exemplo, validar 1 passo e implantar 14 passos).
- Treinar com covariáveis futuras que não estarão disponíveis no momento da inferência.
- Ignorar cobertura sazonal (janelas de treino/validação que perdem períodos importantes).
- Usar poucas dobras e superajustar decisões a uma única janela de validação “sortuda”.
- Ajuste de hiperparâmetros sem divisões que respeitam o tempo (pode ser necessária CV de séries temporais aninhada para seleção de modelo não enviesada).
Juntando Tudo: Uma Receita “Padrão” Prática
Para muitos projetos de previsão, um protocolo de baseline forte é:
- Conjunto de teste final: separar o período mais recente (por exemplo, últimos 2–3 meses) como um teste intocado.
- Dentro do histórico restante, executar CV walk-forward:
- escolher janela expansiva ou móvel com base na deriva
- usar blocos de validação iguais ao seu horizonte de implantação (ou cadência de re-treinamento)
- incluir uma lacuna pelo menos tão grande quanto seu lookback máximo de atributos
- Reportar:
- métrica média ao longo das dobras
- métrica por horizonte (se multi-passos)
- desempenho ao longo do tempo (tendência)
- Somente após a seleção do modelo, avaliar uma vez no conjunto de teste final intocado.
Isso combina seleção robusta de modelo com uma estimativa realista de desempenho “futuro”.
Resumo
A validação cruzada de séries temporais consiste em preservar a causalidade temporal e simular a implantação. As principais ferramentas — janelas expansivas, janelas móveis, CV em blocos e validação walk-forward — são maneiras diferentes de escolher uma sequência de pontos de corte treino/validação. A qualidade prática da sua avaliação frequentemente depende de detalhes: horizonte de previsão, tamanho do passo, lacuna/embargo, cobertura sazonal, disponibilidade de covariáveis e cadência de re-treinamento. Quando bem desenhada, a CV de séries temporais fornece não apenas uma estimativa de acurácia, mas um retrato realista de como um sistema de previsão se comportará ao longo do tempo em produção.