Pandas: Projeto: Séries Temporais
Última atualização: 2026-10-11
A previsão de séries temporais não é apenas sobre modelagem — antes de recorrer a Machine Learning, compreender apenas a tendência e a sazonalidade pode produzir previsões de linha de base sólidas. Nesta lição, usamos a previsão de vendas da cafeteria da Alice como cenário, percorrendo todo o pipeline desde o pré-processamento até a previsão básica com resample + rolling + shift. Esta é uma aplicação prática das ferramentas da Lição 17 e um prelúdio para as próximas lições de ML.
1. O Que Você Aprenderá
- ❶ Pré-processamento de séries temporais
- ❷ Extração de tendência e sazonalidade
- ❸ Previsão com média móvel
- ❹ Decomposição sazonal
- ❺ Avaliação da previsão (MAE/MAPE)
2. Contexto do Projeto: Previsão de Vendas de Cafeteria
(1) Tarefa
Alice quer prever a receita da cafeteria para o próximo mês — os dados históricos têm uma tendência (crescimento constante mês a mês) e sazonalidade (mais bebidas quentes no inverno).
(2) Pipeline de Análise
graph TB
A["1. Pré-processamento<br>resample+fillna"] --> B["2. Extração de Tendência<br>rolling+diff"]
B --> C["3. Análise de Sazonalidade<br>groupby mês"]
C --> D["4. Previsão por Média Móvel<br>rolling mean"]
D --> E["5. Avaliação<br>MAE/MAPE"]
E --> F["6. Previsão Próximo Mês"]
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
3. Pré-processamento de Dados
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: Pré-processamento de Séries Temporais (Dificuldade ⭐⭐)
import pandas as pd
import numpy as np
# ============================================
# Passo 1: Gerar & Pré-processar
# ============================================
np.random.seed(42)
# Gerar 365 dias de vendas com tendência + sazonalidade + ruído
dates = pd.date_range('2023-01-01', periods=365)
trend = np.linspace(300, 450, 365) # tendência de alta
seasonality = 50 * np.sin(2 * np.pi * np.arange(365) / 365 * 2) # ciclo semestral
winter_effect = np.where(dates.month.isin([11, 12, 1, 2]), 30, 0) # impulso no inverno
noise = np.random.normal(0, 20, 365)
daily_sales = pd.DataFrame({
'sales': np.round(trend + seasonality + winter_effect + noise, 0),
'customers': np.round((trend + seasonality + winter_effect + noise) / 8, 0)
}, index=dates)
# Injetar dias faltantes
missing_idx = np.random.choice(365, 15, replace=False)
daily_sales.iloc[missing_idx] = np.nan
# Pré-processar: preencher faltantes → garantir frequência diária
daily_sales = daily_sales.asfreq('D') # garantir que não faltem datas
daily_sales['sales'] = daily_sales['sales'].interpolate(method='time')
daily_sales['customers'] = daily_sales['customers'].interpolate(method='time')
print(f"Período: {daily_sales.index[0].date()} a {daily_sales.index[-1].date()}")
print(f"Faltantes após preenchimento: {daily_sales.isnull().sum().sum()}")
print(f"\nEstatísticas de vendas diárias:\n{daily_sales['sales'].describe()}")
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
4. Extração de Tendência
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: Tendência e Remoção de Tendência (Dificuldade ⭐⭐)
# ============================================
# Passo 2: Extração de Tendência
# ============================================
# Média móvel de 30 dias = tendência
daily_sales['trend'] = daily_sales['sales'].rolling(30, center=True).mean()
# Removido a tendência = real - tendência (mostra sazonalidade + ruído)
daily_sales['detrended'] = daily_sales['sales'] - daily_sales['trend']
# Taxa de crescimento mês a mês
monthly = daily_sales['sales'].resample('M').sum()
monthly_growth = monthly.pct_change() * 100
print("=== Vendas Mensais ===")
print(monthly.tail(6))
print(f"\nCrescimento mensal médio: {monthly_growth.mean():.1f}%")
print(f"Crescimento anual total: {((monthly.iloc[-1] / monthly.iloc[0]) - 1) * 100:.1f}%")
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
5. Análise de Sazonalidade
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: Índice Sazonal (Dificuldade ⭐⭐⭐)
# ============================================
# Passo 3: Análise de Sazonalidade
# ============================================
# Média mensal (de todos os anos)
daily_sales['month'] = daily_sales.index.month
monthly_avg = daily_sales.groupby('month')['sales'].mean()
# Índice sazonal = média mensal / média geral
overall_avg = daily_sales['sales'].mean()
seasonal_index = (monthly_avg / overall_avg).round(3)
print("=== Índice Sazonal ===")
for m, idx in seasonal_index.items():
label = "↑" if idx > 1.05 else ("↓" if idx < 0.95 else "→")
print(f" Mês {m:2d}: {idx:.3f} {label}")
# Padrão do dia da semana
daily_sales['dayofweek'] = daily_sales.index.dayofweek
dow_avg = daily_sales.groupby('dayofweek')['sales'].mean()
dow_names = ['Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb', 'Dom']
print(f"\n=== Média por Dia da Semana ===")
for i, name in enumerate(dow_names):
print(f" {name}: ${dow_avg[i]:.0f}")
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
6. Previsão por Média Móvel
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: Previsão com Média Móvel (Dificuldade ⭐⭐⭐)
# ============================================
# Passo 4: Previsão por Média Móvel
# ============================================
# Divisão treino/teste: últimos 30 dias como teste
train = daily_sales.iloc[:-30]
test = daily_sales.iloc[-30:]
# Previsão simples por média móvel (usa a média dos últimos N dias)
def ma_forecast(train_series, window, horizon):
"""Prever os próximos 'horizon' dias usando média móvel"""
last_ma = train_series.rolling(window).mean().iloc[-1]
return pd.Series([last_ma] * horizon,
index=pd.date_range(train.index[-1] + pd.Timedelta(days=1),
periods=horizon))
# Testar diferentes janelas
for w in [7, 14, 30]:
forecast = ma_forecast(train['sales'], w, 30)
mae = (forecast - test['sales']).abs().mean()
mape = ((forecast - test['sales']) / test['sales']).abs().mean() * 100
print(f"MA({w:2d}): MAE=${mae:.0f}, MAPE={mape:.1f}%")
# Previsão com ajuste sazonal
# previsão = previsão_tendência × índice_sazonal
last_trend = train['sales'].rolling(30).mean().iloc[-1]
monthly_trend_growth = train['sales'].rolling(30).mean().diff(30).mean()
forecast_months = test.index.month
seasonal_forecast = pd.Series(
[(last_trend + monthly_trend_growth * i) * seasonal_index[m]
for i, m in enumerate(forecast_months)],
index=test.index
)
mae_seasonal = (seasonal_forecast - test['sales']).abs().mean()
mape_seasonal = ((seasonal_forecast - test['sales']) / test['sales']).abs().mean() * 100
print(f"\nAjuste sazonal: MAE=${mae_seasonal:.0f}, MAPE={mape_seasonal:.1f}%")
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
7. Avaliação da Previsão
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: Avaliação e Previsão do Próximo Mês (Dificuldade ⭐⭐)
# ============================================
# Passo 5-6: Avaliação & Previsão Próximo Mês
# ============================================
# Métricas de avaliação
def evaluate(actual, forecast, name="Modelo"):
mae = (forecast - actual).abs().mean()
rmse = ((forecast - actual) ** 2).mean() ** 0.5
mape = ((forecast - actual) / actual).abs().mean() * 100
print(f"{name}: MAE=${mae:.0f}, RMSE=${rmse:.0f}, MAPE={mape:.1f}%")
return mae, rmse, mape
# Avaliar melhor modelo
print("=== Avaliação do Modelo ===")
evaluate(test['sales'], ma_forecast(train['sales'], 14, 30), "MA(14)")
evaluate(test['sales'], seasonal_forecast, "Ajuste sazonal")
# Previsão próximo mês (Janeiro 2024)
next_month_days = pd.date_range('2024-01-01', periods=31)
last_trend_full = daily_sales['sales'].rolling(30).mean().iloc[-1]
jan_index = seasonal_index[1]
next_month_forecast = last_trend_full * jan_index
print(f"\n=== Previsão para Janeiro de 2024 ===")
print(f" Previsão diária: ${next_month_forecast:.0f}")
print(f" Previsão mensal: ${next_month_forecast * 31:,.0f}")
print(f" Baseado na tendência: ${last_trend_full:.0f} × índice sazonal: {jan_index:.3f}")
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
❓ Perguntas Frequentes
📖 Resumo
- Pré-processamento: asfreq garante frequência consistente, depois interpolate preenche valores faltantes
- Tendência: média móvel rolling(30); diff revela a taxa de mudança
- Sazonalidade: média mensal / média geral = índice sazonal
- Previsão: média móvel (simples) → tendência × índice sazonal (melhorado)
- Avaliação: MAE (erro absoluto) / RMSE (raiz do erro quadrático médio) / MAPE (porcentagem)
- Horizonte de previsão confiável ≈ 1/3 do comprimento dos dados históricos; a média móvel serve como a linha de base para ML
📝 Exercícios
- Básico (Dificuldade ⭐): Gere 180 dias de dados de vendas (com uma tendência), agregue para totais mensais com resample('M'), e calcule a taxa de crescimento mês a mês.
- Intermediário (Dificuldade ⭐⭐): Gere 365 dias de dados com sazonalidade, extraia uma linha de tendência de 30 dias, compute o índice sazonal de 12 meses, e identifique as temporadas alta e baixa.
- Desafio (Dificuldade ⭐⭐⭐): Complete um projeto de previsão completo: pré-processamento → tendência + sazonalidade → previsões MA(7/14/30) → previsão com ajuste sazonal → avaliação MAPE → saída da previsão para o próximo mês.
← Anterior: Projeto - Análise de Dados · Próximo: Projeto - Análise Abrangente →