La serie de tiempo elegida es la Tasa Representativa del Mercado (TRM) semanal del par peso colombiano–Dólar estadounidense, medida cada viernes desde 2016 hasta 2025. Este dataset cumple con las condiciones de serie de tiempo, debido a que:
# Carga de datos
datos <- read.csv(
"C:/Users/almun/OneDrive - Universidad Nacional de Colombia/Escritorio/Undecimo semestre/Metodos cuantitativos/Taller 2 predictivo/trm.csv",
sep = ";",
stringsAsFactors = FALSE
)
datos$fecha <- as.Date(datos$fecha, format = "%d/%m/%Y")
# Partición: entrenamiento (todos menos últimos 3) y prueba (últimos 3)
N_total <- nrow(datos)
train_df <- datos[1:(N_total-3), ]
test_df <- datos[(N_total-2):N_total, ]
# Serie de tiempo semanal (frecuencia = 52)
start_sem <- c(year(min(train_df$fecha)), isoweek(min(train_df$fecha)))
trm_ts <- ts(train_df$trm, start = start_sem, frequency = 52)
# Descomposición STL
stl_dec <- stl(trm_ts, s.window = "periodic")
# Guardamos componentes y mostramos primeras 6 filas
componentes <- as_tibble(stl_dec$time.series)
head(componentes, 6)
## # A tibble: 6 × 3
## seasonal trend remainder
## <dbl> <dbl> <dbl>
## 1 -28.5 3046. 53.3
## 2 -2.09 3042. 59.9
## 3 16.8 3039. 108.
## 4 -0.577 3036. 153.
## 5 -29.2 3033. 57.6
## 6 -50.2 3029. 23.6
Horizonte de pronóstico: h = 3 (últimas 3 semanas).
# 2. Pronósticos y tablas comparativas (versión sin accuracy())
#
# En este bloque hacemos h = 3 predicciones, construimos las tablas
# de Fecha / Real / Predicción y calculamos manualmente:
# RMSE = sqrt(mean((pred - real)^2))
# MAE = mean(abs(pred - real))
# MAPE = mean(abs((pred - real) / real)) * 100
# Guardamos cada métrica en metrics_list para el resumen final.
h <- 3
fechas_test <- test_df$fecha
reales <- test_df$trm
metrics_list <- list()
procesar_modelo <- function(nombre, fc_obj = NULL, preds = NULL) {
if (!is.null(fc_obj) && inherits(fc_obj, "forecast")) {
estimados <- as.numeric(fc_obj$mean)
} else if (!is.null(preds)) {
estimados <- as.numeric(preds)
} else {
stop("Debe proveer un objeto 'forecast' o un vector 'preds'.")
}
errores <- estimados - reales
rmse <- sqrt(mean(errores^2))
mae <- mean(abs(errores))
mape <- mean(abs(errores / reales)) * 100
tabla <- tibble(
Modelo = nombre,
Fecha = fechas_test,
Real = reales,
Predicción = round(estimados, 2),
RMSE = round(rmse, 2),
MAE = round(mae, 2),
MAPE = round(mape, 2)
)
cat("\n### Modelo:", nombre, "\n")
print(tabla)
metrics_list[[nombre]] <<- c(RMSE = rmse, MAE = mae, MAPE = mape)
}
# 2.1 Promedios Móviles
ma_fc <- forecast(ma(trm_ts, order = 8), h = h)
procesar_modelo("Promedios Móviles", fc_obj = ma_fc)
##
## ### Modelo: Promedios Móviles
## # A tibble: 3 × 7
## Modelo Fecha Real Predicción RMSE MAE MAPE
## <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Promedios Móviles 2025-04-04 4274. 4095. 202. 198. 4.6
## 2 Promedios Móviles 2025-04-11 4338. 4085. 202. 198. 4.6
## 3 Promedios Móviles 2025-04-25 4240. 4080. 202. 198. 4.6
# 2.2 Suavización Exponencial Simple (SES)
ses_fc <- ses(trm_ts, h = h)
procesar_modelo("SES", fc_obj = ses_fc)
##
## ### Modelo: SES
## # A tibble: 3 × 7
## Modelo Fecha Real Predicción RMSE MAE MAPE
## <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 SES 2025-04-04 4274. 4191. 101. 92.8 2.16
## 2 SES 2025-04-11 4338. 4191. 101. 92.8 2.16
## 3 SES 2025-04-25 4240. 4191. 101. 92.8 2.16
# 2.3 Índices Estacionales (CES simple)
ces_fc <- forecast(ces(trm_ts, h = h, seasonality = "simple"), h = h)
procesar_modelo("CES Simple", fc_obj = ces_fc)
##
## ### Modelo: CES Simple
## # A tibble: 3 × 7
## Modelo Fecha Real Predicción RMSE MAE MAPE
## <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 CES Simple 2025-04-04 4274. 4317. 72.9 57.8 1.36
## 2 CES Simple 2025-04-11 4338. 4351. 72.9 57.8 1.36
## 3 CES Simple 2025-04-25 4240. 4358. 72.9 57.8 1.36
# 2.4 Regresiones Polinómicas con I():
Tiempo <- seq_along(trm_ts)
nuevos <- data.frame(Tiempo = length(trm_ts) + seq_len(h))
# Lineal
mod_lin <- lm(trm_ts ~ Tiempo)
fc_lin <- forecast(mod_lin, newdata = nuevos)
procesar_modelo("Regresión Lineal", fc_obj = fc_lin)
##
## ### Modelo: Regresión Lineal
## # A tibble: 3 × 7
## Modelo Fecha Real Predicción RMSE MAE MAPE
## <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Regresión Lineal 2025-04-04 4274. 4516. 240. 236. 5.51
## 2 Regresión Lineal 2025-04-11 4338. 4520. 240. 236. 5.51
## 3 Regresión Lineal 2025-04-25 4240. 4524. 240. 236. 5.51
# Cuadrático
mod_cua <- lm(trm_ts ~ Tiempo + I(Tiempo^2))
fc_cua <- forecast(mod_cua, newdata = nuevos)
procesar_modelo("Regresión Cuadrática", fc_obj = fc_cua)
##
## ### Modelo: Regresión Cuadrática
## # A tibble: 3 × 7
## Modelo Fecha Real Predicción RMSE MAE MAPE
## <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Regresión Cuadrática 2025-04-04 4274. 4313. 51.4 46.4 1.09
## 2 Regresión Cuadrática 2025-04-11 4338. 4315. 51.4 46.4 1.09
## 3 Regresión Cuadrática 2025-04-25 4240. 4316. 51.4 46.4 1.09
# Cúbico
mod_cub <- lm(trm_ts ~ Tiempo + I(Tiempo^2) + I(Tiempo^3))
fc_cub <- forecast(mod_cub, newdata = nuevos)
procesar_modelo("Regresión Cúbica", fc_obj = fc_cub)
##
## ### Modelo: Regresión Cúbica
## # A tibble: 3 × 7
## Modelo Fecha Real Predicción RMSE MAE MAPE
## <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Regresión Cúbica 2025-04-04 4274. 3957. 338. 336. 7.83
## 2 Regresión Cúbica 2025-04-11 4338. 3948. 338. 336. 7.83
## 3 Regresión Cúbica 2025-04-25 4240. 3939. 338. 336. 7.83
# 2.5 Análisis de Correlación TRM ~ Brent
mod_corr <- lm(trm ~ brent, data = train_df)
pred_corr <- predict(mod_corr, newdata = test_df)
procesar_modelo("Correlación TRM~Brent", preds = pred_corr)
##
## ### Modelo: Correlación TRM~Brent
## # A tibble: 3 × 7
## Modelo Fecha Real Predicción RMSE MAE MAPE
## <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Correlación TRM~Brent 2025-04-04 4274. 3724. 637. 632. 14.8
## 2 Correlación TRM~Brent 2025-04-11 4338. 3603. 637. 632. 14.8
## 3 Correlación TRM~Brent 2025-04-25 4240. 3628. 637. 632. 14.8
# 2.6 Modelo ARIMA automático
mod_arima <- auto.arima(trm_ts)
fc_arima <- forecast(mod_arima, h = h)
procesar_modelo("ARIMA", fc_obj = fc_arima)
##
## ### Modelo: ARIMA
## # A tibble: 3 × 7
## Modelo Fecha Real Predicción RMSE MAE MAPE
## <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 ARIMA 2025-04-04 4274. 4201. 98.0 89.3 2.08
## 2 ARIMA 2025-04-11 4338. 4193. 98.0 89.3 2.08
## 3 ARIMA 2025-04-25 4240. 4190. 98.0 89.3 2.08
Realizamos un resumen de las metricas
metrics_df <- bind_rows(
lapply(names(metrics_list), function(m) {
tibble(
Modelo = m,
RMSE = round(metrics_list[[m]]["RMSE"], 2),
MAE = round(metrics_list[[m]]["MAE"], 2),
MAPE = round(metrics_list[[m]]["MAPE"], 2)
)
})
)
print(metrics_df)
## # A tibble: 8 × 4
## Modelo RMSE MAE MAPE
## <chr> <dbl> <dbl> <dbl>
## 1 Promedios Móviles 202. 198. 4.6
## 2 SES 101. 92.8 2.16
## 3 CES Simple 72.9 57.8 1.36
## 4 Regresión Lineal 240. 236. 5.51
## 5 Regresión Cuadrática 51.4 46.4 1.09
## 6 Regresión Cúbica 338. 336. 7.83
## 7 Correlación TRM~Brent 637. 632. 14.8
## 8 ARIMA 98.0 89.3 2.08
## SES
## CES Simple
## Regresión Lineal
## Regresión Cuadrática
## Regresión Cúbica
## Correlación TRM~Brent
## ARIMA automático
Para nuestro ejercicio escogimos el modelo de Regresión Cuadrática como el que se ajusta más a nuestras necesidades (predición de la TRM semanal), porque en el conjunto de prueba alcanzó las métricas más bajas de todos:
RMSE = 51.36
MAE = 46.44
MAPE = 1.09 %
Estos valores nos indican que, en promdio, sus predicciones se desvían en menor medida de los datos reales y capturan mejor la forma no lineal de nuestra serie de tiempo
No escogimos el modelo con el segundo mejor desempeño,CES Simple, con RMSE = 72.88, MAE = 57.84 y MAPE = 1.36% porque todos sus errores son sensiblemente mayores: su MAPE es 0.27 puntos porcentuales superior y sus errores absolutos (RMSE/MAE) rondan entre 10 y 20 unidades de TRM más, lo cual resulta en un peor pronostico.
# Grafica del ultimo año de nuestra serie, incluyendo las predicicones y los datos reales
# Definimos el ultimo año
fecha_max <- max(datos$fecha)
fecha_inicio <- fecha_max - years(1)
df_ult_ano <- datos %>%
filter(fecha >= fecha_inicio)
# Predicciones del mejor modelo (Regresión Cuadrática)
df_pred <- tibble(
fecha = fechas_test,
Pred = as.numeric(fc_cua$mean)
)
ggplot(df_ult_ano, aes(x = fecha, y = trm)) +
geom_line(color = "steelblue", size = 0.8) +
geom_point(data = df_pred, aes(x = fecha, y = Pred),
color = "firebrick", size = 3) +
labs(
title = "TRM Semanal: Último Año y Pronósticos",
x = "Fecha",
y = "TRM"
) +
theme_minimal()