Séries Temporais e a Evolução da Modelagem de Sequências
Analisar uma série temporal é, em essência, uma forma de “modelagem de sequências”. O objetivo é entender os padrões em dados ordenados no tempo para prever o que virá a seguir, e os diferentes tipos de modelos criados ao longo da história da análise de séries temporais até o dias atuais é extensivo. Entre alguns deles, temos:
- Modelos Clássicos (Ex: ARIMA): Eficazes para séries com padrões lineares e estacionários, mas limitados ao capturar relações mais complexas e não-lineares.
- Redes Neurais Recorrentes (Ex: RNNs): Introduziram o conceito de “memória”, processando sequências passo a passo e mantendo um estado interno. No entanto, sofriam para reter informações de longo prazo, um problema conhecido como gradiente descendente.
- LSTMs e GRUs: Variações das RNNs com “portões” (gates) que controlam o fluxo de informação, melhorando a capacidade de aprender dependências de longo prazo. Apesar do grande avanço, elas ainda processam os dados de forma sequencial, o que pode ser um gargalo computacional.
É neste ponto que os Transformers surgem, quebrando o paradigma do processamento sequencial e introduzindo uma forma mais poderosa de “lembrar” o passado: a atenção.
Objetivo
- Aplicações Práticas com Bibliotecas Python: Mostraremos como aplicar esses conceitos em séries temporais usando bibliotecas populares. O foco será em entender a lógica por trás do uso prático dessa tecnologia.
Transformers em Séries Temporais: Como é Possível?
A transição dos Transformers do texto para as séries temporais é conceitualmente direta. Em NLP, um Transformer trata cada palavra (ou “token”) em uma frase como uma unidade. Em uma série temporal, cada observação (ex: o valor diário do câmbio) é tratada como um “token”.
A sequência de valores ao longo do tempo se torna uma “frase”, e o Transformer aprende a gramática e o contexto dessa “frase” temporal.
# Exemplo simbólico: sequência temporal como "frases"
# Cada valor é um "token" que o Transformer analisa em relação aos outros.
serie_juros = [12.50, 12.75, 13.25, 13.75, 13.75, 13.25, 12.75]
# O Transformer pode aprender que a primeira ocorrência de 12.75,
# mesmo distante, é um forte indicador para a ocorrência futura de 13.25,
# ignorando os valores intermediários se não forem relevantes.
Adaptar uma arquitetura de texto para números ordenados no tempo parece um salto, mas a analogia é direta: uma série temporal é tratada como uma frase, onde cada observação é uma palavra. No entanto, essa adaptação traz desafios, vantagens e desvantagens.
Os Desafios e as Soluções
- Problema: Falta de Noção de Ordem. Como mencionado, o self-attention é invariante à permutação.
- Solução: O Positional Encoding é crucial. Ele injeta a informação temporal diretamente nos dados de entrada, permitindo que o modelo aprenda a importância da ordem.
- Problema: Complexidade Quadrática. O self-attention compara cada ponto com todos os outros. Para uma série com
Npontos, isso exigeN²cálculos. Para séries temporais muito longas (milhares ou milhões de pontos), isso se torna computacionalmente inviável.- Solução: Pesquisas recentes criaram variações mais eficientes, como o Informer e o LogSparse Transformer, que usam mecanismos de atenção “esparsos”, focando apenas nos pontos mais relevantes e reduzindo drasticamente a complexidade.
- Problema: Dados Contínuos vs. Discretos. Texto é formado por tokens discretos (palavras). Séries temporais são contínuas.
- Solução: Tratamos cada ponto de observação como um token discreto e o transformamos em um embedding, permitindo que o modelo opere sobre eles da mesma forma que faria com palavras.
Vantagens
- Captura de Dependências de Longo Prazo: Esta é a maior vantagem sobre LSTMs. Um Transformer pode, teoricamente, conectar um evento de hoje (ex: uma queda na bolsa) a uma crise financeira ocorrida há vários anos, simplesmente porque o mecanismo de atenção pode criar uma ligação direta entre esses dois pontos no tempo, sem que a informação se degrade ao longo do caminho.
- Paralelização: Ao contrário das RNNs, que precisam processar os dados sequencialmente, o Transformer processa a série inteira de uma vez. Isso o torna muito mais rápido para treinar em hardware moderno (GPUs/TPUs).
- Interpretabilidade: Os mapas de atenção podem ser visualizados, permitindo entender em quais pontos do passado o modelo está “prestando mais atenção” para fazer uma previsão, o que ajuda a abrir a “caixa-preta”.
Desvantagens
- Exigência de Dados: Transformers são modelos grandes com milhões de parâmetros. Eles precisam de grandes volumes de dados para serem treinados de forma eficaz e evitar o superajuste (overfitting).
- Complexidade (fora da caixa): Como mencionado, a complexidade quadrática torna o Transformer “vanilla” inadequado para séries temporais muito longas. É necessário recorrer a variantes mais complexas e recentes.
- Menos “Viés Indutivo” para o Tempo: RNNs são construídas com a premissa de sequencialidade. Transformers não têm essa premissa e dependem inteiramente do Positional Encoding para aprender a ordem. Em conjuntos de dados menores, essa falta de um viés estrutural pode levar a um desempenho inferior.
Bibliotecas Python para Aplicar Transformers em Séries Temporais
Felizmente, não é preciso construir um Transformer do zero. Diversas bibliotecas Python de alto nível já implementam modelos baseados em Transformers, facilitando sua aplicação.
1. Darts
Darts é uma biblioteca Python de código aberto projetada para tornar a previsão e análise de séries temporais mais acessível e eficiente. Desenvolvida pela Unit8, ela oferece uma API consistente e simples, semelhante à do scikit-learn, que permite aos usuários aplicar uma vasta gama de modelos de previsão, desde os clássicos como ARIMA e Suavização Exponencial até modelos avançados de aprendizado profundo como LSTMs, N-BEATS e Transformers.
Principais Características: * API Unificada: A principal vantagem do Darts é sua interface fit() e predict() padronizada para todos os modelos, o que simplifica a experimentação e a comparação entre diferentes abordagens. * Suporte Amplo: Lida tanto com séries temporais univariadas quanto multivariadas e oferece suporte a previsões probabilísticas para quantificar a incerteza. * Backtesting e Avaliação: Inclui ferramentas robustas para backtesting de modelos, permitindo simular previsões históricas em janelas de tempo móveis e avaliar a performance com diversas métricas. * Integração: É compatível com estruturas de dados populares como Pandas DataFrames, NumPy arrays e PyTorch Tensors, facilitando a manipulação e o pré-processamento dos dados.
!pip install darts --quiet
import numpy as np
import pandas as pd
from darts import TimeSeries
from darts.models import TransformerModel
# 1. Geração de Dados Sintéticos
n_pontos = 200
tempo = np.arange(n_pontos)
# Série senoidal com um pouco de ruído
valores = np.sin(tempo / 10) + np.random.normal(0, 0.1, n_pontos)
df = pd.DataFrame({
'time': pd.to_datetime(pd.date_range(start='2023-01-01', periods=n_pontos, freq='D')),
'value': valores
})
series = TimeSeries.from_dataframe(df, 'time', 'value')
# 2. Preparação dos Dados
train, val = series.split_before(0.8) # 80% para treino
# 3. Definição e Treinamento do Modelo
# input_chunk_length: quantos passos no tempo o modelo vê para fazer uma previsão
# output_chunk_length: quantos passos no tempo o modelo prevê de uma vez
model = TransformerModel(
input_chunk_length=24,
output_chunk_length=12,
n_epochs=50,
random_state=42
)
model.fit(train, verbose=False)
# 4. Previsão e Resultado
horizonte_previsao = 36
previsao = model.predict(n=horizonte_previsao)
print("--- Darts Transformer ---")
print("Previsão para os próximos {} dias:".format(horizonte_previsao))
print(previsao.pd_dataframe())
2. GluonTS
Desenvolvida pela Amazon, a GluonTS é uma biblioteca Python focada em modelos de deep learning para previsão de séries temporais, com uma ênfase especial em previsão probabilística. Em vez de prever um único valor, os modelos da GluonTS aprendem uma distribuição de probabilidade, permitindo a geração de intervalos de confiança e cenários alternativos, o que é crucial para a tomada de decisão sob incerteza.
Principais Características: * Foco em Previsão Probabilística: É a sua principal fortaleza, permitindo que os usuários capturem a incerteza inerente às previsões. * Modelos de Ponta: Inclui implementações de referência de modelos estado da arte, como DeepAR e o próprio Transformer, facilitando o benchmarking. * Escalabilidade: Projetada para lidar com grandes conjuntos de dados contendo múltiplas séries temporais, treinando um único modelo global que aprende padrões a partir de todas as séries. * Modularidade: Oferece componentes modulares, como transformações de features e distribuições de probabilidade, que podem ser combinados para criar novos modelos personalizados.
!pip install gluonts --quiet
import numpy as np
import pandas as pd
from gluonts.dataset.common import ListDataset
from gluonts.model.transformer import TransformerEstimator
from gluonts.mx.trainer import Trainer
import mxnet as mx
# Semente para reprodutibilidade
mx.random.seed(42)
np.random.seed(42)
# 1. Geração de Dados Sintéticos
n_pontos = 200
valores = np.sin(np.arange(n_pontos) / 10) + np.random.normal(0, 0.1, n_pontos)
start_date = "2023-01-01"
# 2. Preparação dos Dados (formato GluonTS)
# GluonTS requer um dicionário com 'start' (timestamp) e 'target' (valores)
training_data = ListDataset(
[{"start": pd.to_datetime(start_date), "target": valores[:-36]}],
freq="D"
)
# 3. Definição e Treinamento do Modelo
estimator = TransformerEstimator(
freq="D",
prediction_length=36, # Horizonte de previsão
context_length=50, # Quantos pontos passados o modelo deve ver
trainer=Trainer(epochs=10)
)
predictor = estimator.train(training_data)
# 4. Previsão e Resultado
# Para a previsão, precisamos fornecer os dados de teste
test_data = ListDataset(
[{"start": pd.to_datetime(start_date), "target": valores}],
freq="D"
)
print("\n--- GluonTS Transformer ---")
for test_entry, forecast in zip(test_data, predictor.predict(test_data)):
# A previsão é probabilística, então pegamos a média
mean_forecast = forecast.mean
print(f"Previsão (média) para os próximos {len(mean_forecast)} dias:")
print(mean_forecast)
3. Hugging Face Transformers
Originalmente o epicentro da revolução do NLP, a biblioteca da Hugging Face expandiu seu escopo e agora oferece modelos para diversas modalidades, incluindo séries temporais. O Time Series Transformer é uma implementação da arquitetura vanilla de encoder-decoder para tarefas de previsão.
Principais Características: * Ecossistema Integrado: Beneficia-se de todo o ecossistema da Hugging Face, incluindo ferramentas para compartilhamento de modelos, datasets e treinamento. * Previsão Probabilística: Assim como o GluonTS, o modelo de Transformer da Hugging Face é um modelo de previsão probabilística, aprendendo uma distribuição a partir da qual as previsões podem ser amostradas. * Flexibilidade de Features: Permite a inclusão fácil de features temporais (como dia do mês, mês do ano) tanto para o passado quanto para o futuro, que funcionam como “codificações posicionais” para o encoder e o decoder. * Treinamento com “Teacher-Forcing”: Utiliza uma técnica de treinamento eficiente e padrão para modelos de sequência, onde a entrada correta do passo de tempo anterior é fornecida como entrada para o passo de tempo atual.
!pip install transformers --quiet
import numpy as np
import torch
from transformers import TimeSeriesTransformerForPrediction, TimeSeriesTransformerConfig
# 1. Geração de Dados Sintéticos
n_pontos = 200
context_length = 60
prediction_length = 20
valores = np.sin(np.arange(n_pontos) / 10) + np.random.normal(0, 0.1, n_pontos)
# 2. Preparação dos Dados (formato Tensor)
# O modelo espera um tensor com shape (batch_size, context_length)
past_values = torch.tensor(valores[:-prediction_length]).float()
past_values = past_values[-context_length:].unsqueeze(0)
# 3. Definição do Modelo
config = TimeSeriesTransformerConfig(
prediction_length=prediction_length,
context_length=context_length,
input_size=1,
# Parâmetros da arquitetura
encoder_layers=2,
decoder_layers=2,
d_model=16,
)
model = TimeSeriesTransformerForPrediction(config)
# 4. Previsão e Resultado
# O método .generate() faz a previsão sem necessidade de treinamento explícito aqui
# (usando os pesos iniciais aleatórios, para fins de demonstração)
# Em um caso real, o modelo seria treinado com um loop de treinamento PyTorch.
outputs = model.generate(
static_categorical_features=None,
past_time_features=None,
past_values=past_values,
future_time_features=None,
)
print("\n--- Hugging Face Transformer ---")
print(f"Previsão para os próximos {prediction_length} dias:")
# A saída tem shape (batch_size, num_samples, prediction_length)
# Pegamos o primeiro batch e a média das amostras
predicted_mean = outputs.sequences.mean(dim=1)
print(predicted_mean[0])
Conclusão
Os Transformers representam uma mudança de paradigma na análise de séries temporais. Sua capacidade de capturar dependências complexas de longo prazo e a flexibilidade de sua arquitetura os tornam uma ferramenta indispensável para lidar com a complexidade dos dados do mundo real. Com o surgimento de bibliotecas acessíveis, a aplicação desses modelos poderosos está cada vez mais ao alcance de cientistas de dados e analistas financeiros.
Referências
AHMED, Sabeen; NIELSEN, Ian E.; TRIPATHI, Aakash; SIDDIQUI, Shamoon; RAMACHANDRAN, Ravi P.; RASOOL, Ghulam. Transformers in Time-Series Analysis: A Tutorial. Circuits, Systems, and Signal Processing, v. 42, n. 12, p. 7433-7466, 2023. Disponível em: https://researchwithrowan.com.
ALAMMAR, Jay; GROOTENDORST, Maarten. Hands-On Large Language Models: Language Understanding and Generation. Sebastopol: O’Reilly Media, 2024.
Vaswani, Ashish, Noam Shazeer, Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N Gomez, Lukasz Kaiser, and Illia Polosukhin. 2017. “Attention Is All You Need.” arXiv Preprint arXiv:1706.03762.
NYANDWI, Jean. The Transformer Blueprint: A Holistic Guide to the Transformer Neural Network Architecture. 2023. Disponível em: https://deeprevision.github.io/posts/001-transformer/