Lista 16 · Séries temporais¶
Acompanha o capítulo 16. Média móvel, perfil de um ciclo, suavização exponencial e o erro de uma previsão — medido sempre em dados que o método não viu.
Como esta lista funciona
Abra o caderno no Colab, escreva a sua solução no lugar do # TODO e rode a
célula de teste logo abaixo. Ela mesma diz o que passou e o que falhou — você
não precisa esperar correção de ninguém.
O código de cada exercício também está aqui embaixo, caso você prefira colar num editor local. Os testes comparam números com tolerância.
Exercícios marcados com ✏️ são à mão, no papel, com 4 casas decimais — como na parte em papel das avaliações.
Exercício 01¶
✏️ À mão. Uma série tem os valores 10, 12, 11, 15, 14, 16.
a) Calcule a média móvel com janela de 3 (cada valor é a média de 3 seguidos, a partir do primeiro).
b) Aplique a suavização exponencial com \(\alpha = 0{,}5\), começando com a previsão igual ao primeiro valor: \(\hat y_{t+1} = 0{,}5\,y_t + 0{,}5\,\hat y_t\). Qual a previsão para o sétimo valor?
c) Se o sétimo valor for 17, qual o erro absoluto de cada previsão: a da suavização e a "ingênua" (repetir o último)?
Exercício 02¶
Escreva media_movel(serie, janela), que devolve um array com a média de cada grupo de
janela valores seguidos: o primeiro elemento é a média de serie[0:janela], o
segundo, de serie[1:janela + 1], e assim por diante.
import numpy as np
def media_movel(serie, janela):
"""Array com a média de cada janela de valores seguidos (sem as pontas incompletas)."""
n = len(serie) - janela + 1
medias = np.zeros(n)
# TODO: para cada i, a média da fatia serie[i:i + janela]
return medias
# --- testes (não altere) ---
m = media_movel([10.0, 12.0, 11.0, 15.0, 14.0, 16.0], 3)
esperado = [11.0, 38 / 3, 40 / 3, 15.0]
assert len(m) == 4, "6 valores com janela 3: 4 médias"
for i in range(4):
assert abs(m[i] - esperado[i]) < 1e-12
assert len(media_movel([1.0, 2.0, 3.0], 3)) == 1
print("Exercício 02: todos os testes passaram!")
Exercício 03¶
Escreva mae(previsto, real), o erro absoluto médio: a média de
\(|\hat y_i - y_i|\). Converta as duas entradas com np.array (podem chegar como listas).
import numpy as np
def mae(previsto, real):
"""Erro absoluto médio."""
# TODO: np.array nas duas, abs da diferença e np.mean
pass
# --- testes (não altere) ---
assert abs(mae([10, 12, 11], [11, 12, 14]) - 4 / 3) < 1e-12
assert mae([5, 5], [5, 5]) == 0
print("Exercício 03: todos os testes passaram!")
Exercício 04¶
Escreva rmse(previsto, real), a raiz do erro quadrático médio:
\(\sqrt{\frac{1}{n}\sum (\hat y_i - y_i)^2}\).
Para os mesmos erros, por que o RMSE é sempre maior ou igual ao MAE? Quando são iguais?
import numpy as np
def rmse(previsto, real):
"""Raiz do erro quadrático médio."""
# TODO: a diferença, o quadrado, a média e a raiz
pass
# --- testes (não altere) ---
assert abs(rmse([10, 12, 11], [11, 12, 14]) - (10 / 3) ** 0.5) < 1e-12
assert abs(rmse([0, 0], [3, 3]) - 3) < 1e-12, "todos os erros iguais: RMSE = MAE"
print("Exercício 04: todos os testes passaram!")
Exercício 05¶
O ciclo típico. Escreva perfil_ciclo(serie, periodo), que devolve um array com
periodo valores: o valor da posição \(k\) é a média de serie[k], serie[k + periodo],
serie[k + 2*periodo]... — a fatia serie[k::periodo].
Com periodo = 24 numa série horária, é o "dia típico".
import numpy as np
def perfil_ciclo(serie, periodo):
"""Média de cada posição do ciclo: perfil[k] = média de serie[k], serie[k + periodo], ..."""
perfil = np.zeros(periodo)
# TODO: para cada posição k, a média da fatia serie[k::periodo]
return perfil
# --- testes (não altere) ---
import numpy as np
p = perfil_ciclo(np.array([1.0, 5.0, 2.0, 3.0, 7.0, 4.0]), 3)
for i in range(3):
assert abs(p[i] - [2, 6, 3][i]) < 1e-12, f"veio {p}"
print("Exercício 05: todos os testes passaram!")
Exercício 06¶
Escreva suavizacao(serie, alpha), que começa com a previsão igual ao primeiro valor e,
para cada valor da série (inclusive o primeiro), atualiza
\(\hat y \leftarrow \alpha\,y + (1 - \alpha)\,\hat y\). Devolva a previsão final — a do
próximo valor.
def suavizacao(serie, alpha):
"""Previsão para o próximo valor pela suavização exponencial simples."""
previsao = serie[0]
# TODO: um laço pela série, atualizando a previsão
return previsao
# --- testes (não altere) ---
assert abs(suavizacao([10.0, 12.0, 11.0, 15.0, 14.0, 16.0], 0.5) - 14.75) < 1e-12
assert abs(suavizacao([10.0, 12.0, 11.0, 15.0, 14.0, 16.0], 1.0) - 16.0) < 1e-12, "alpha = 1: o último valor"
assert abs(suavizacao([10.0, 12.0, 11.0, 15.0, 14.0, 16.0], 0.0) - 10.0) < 1e-12, "alpha = 0: nunca sai do primeiro"
print("Exercício 06: todos os testes passaram!")
Exercício 07¶
Telecom — prever o tráfego. O tráfego de uma rede se repete a cada dia. Escreva
previsao_sazonal(serie, periodo, passos), que prevê os próximos passos valores
copiando, para cada um, o valor de um período atrás. Quando passos for maior que
periodo, a previsão passa a copiar os próprios valores previstos: por isso, vá
acrescentando cada previsão ao histórico.
import numpy as np
def previsao_sazonal(serie, periodo, passos):
"""Os próximos `passos` valores, copiando o valor de um período atrás."""
historico = list(serie)
previsao = []
# TODO: para cada passo, o valor de um período atrás no histórico; guarde na
# previsão E no histórico
return np.array(previsao)
# --- testes (não altere) ---
p = previsao_sazonal([5, 9, 7, 6, 10, 8], 3, 4)
esperado = [6, 10, 8, 6]
assert len(p) == 4
for i in range(4):
assert p[i] == esperado[i], f"veio {p}"
print("Exercício 07: todos os testes passaram!")