Este análisis se enfoca en una empresa Exportadora de Café que busca diversificar su riesgo y optimizar su estrategia comercial entendiendo el consumo interno en Colombia. Aunque el fuerte de la empresa es la exportación, el mercado doméstico actúa como un amortiguador crítico frente a la volatilidad de los precios internacionales y las variaciones en la tasa de cambio.
Para este estudio, se han seleccionado las siguientes variables macroeconómicas que componen el combo de “Poder de Compra del Hogar”:
Importancia: Esta combinación permite entender no solo qué está pasando con las ventas, sino el porqué (liquidez, confianza y precios), facilitando decisiones estratégicas sobre inventarios y campañas de marketing local.
Instalar/Cargar librerías necesarias
# Cargar librerías necesarias
library(readxl) # Para leer archivos Excel
library(tseries) # Para pruebas de estacionariedad
library(forecast) # Para modelado ARIMA y pronósticos
library(ggplot2) # Para visualización de datos
library(plotly) # Para gráficos interactivos
library(dplyr) # Para manipulación de datos
Cargar base de datos
# Carga de la base de datos completa (hasta Dic 2025)
data_col <- read_excel("Base Caso2_complete.xlsx")
# Verificar las primeras filas
head(data_col)
| FECHA | PNCEM | DECEM | CONCRETO | LICC | POLLO | HUEVO | PNCAFE | PICAFE | PECAFE | XCAF | M | X | TRM | M_CEREAL | M_CERAMICO | M_FARM | X_COMB | X_AZU | X_PREALIM | X_FARM | X_QUIM | X_PAPEL | X_CERAMICO | IPIR | IPIR_PAPEL | IPIR_FARM | IPIR_PREALIM | MIN | ICC | VEH | CART | DAH | ENER | BRENT | IPC | TO | TD | ISE | CAN | AZUCAR | CEM_V | COR_V | M_V | X_V | IPIR_V | MIN_V | ICC_V | VEH_V | PEAJE_V | ENER_V | CART_V | POLLO_V | ENER_CALI | LICC_CALI | VEH_CALI | X_CALI | OCUP_HOTEL_CALI | ICC_CALI | PEAJE_CALI | DAH_CALI | IPIR_CALI |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2012-01-01 | 868474 | 823283.7 | 526135.5 | 1498909 | 91721.61 | 52928.85 | 535 | 874862.9 | 256.1168 | 197295.8 | 4187750 | 4785773 | 1847.516 | 130488.7 | 22662.56 | 134163.0 | 3313842 | 63273.73 | 28018.43 | 30866.08 | 25715.95 | 38768.11 | 11391.80 | 84.22582 | NA | NA | NA | 68.95512 | 32.7 | NA | 2.797604e+14 | 1.261248e+14 | 1595.273 | 111.15619 | 76.75 | 59.6727 | 12.7911 | 81.68037 | 1685584 | 148482.7 | 61149.38 | 109.7525 | 355074079 | 159599364 | 80.69007 | NA | 20.64948 | 2379 | 220673 | 200.3 | 2.596325e+13 | 13518.16 | 69379734 | 71805 | NA | 2776386323 | 40.98415 | 20.64948 | 27041 | 4.071660e+12 | 96.47151 |
| 2012-02-01 | 865408 | 846615.1 | 584896.7 | 1728147 | 94142.30 | 52870.40 | 571 | 826219.8 | 246.3010 | 186693.3 | 4291881 | 4999318 | 1786.543 | 170760.2 | 22217.55 | 144190.3 | 3319381 | 63131.04 | 30393.01 | 31201.81 | 27501.57 | 32519.62 | 15168.11 | 87.97827 | NA | NA | NA | 67.77499 | 26.8 | NA | 2.808113e+14 | 1.297710e+14 | 1544.653 | 119.70238 | 77.22 | 60.5054 | 12.0750 | 84.51632 | 1973654 | 192196.2 | 66968.57 | 112.8675 | 556359400 | 180240665 | 89.67271 | NA | 16.22099 | 2654 | 215773 | 201.4 | 2.612710e+13 | 13579.57 | 68346783 | 60566 | NA | 3334123499 | 48.16395 | 16.22099 | 28333 | 4.093730e+12 | 101.89722 |
| 2012-03-01 | 998847 | 950452.9 | 634905.0 | 1425267 | 88748.18 | 52979.25 | 576 | 727564.5 | 226.0661 | 203636.0 | 4632763 | 5712355 | 1767.793 | 150305.8 | 17682.10 | 158930.0 | 3870611 | 78703.91 | 29172.08 | 35073.98 | 30545.46 | 37829.72 | 14769.90 | 94.12009 | NA | NA | NA | 73.34700 | 24.4 | NA | 2.843590e+14 | 1.282989e+14 | 1718.766 | 124.92864 | 77.31 | 61.5487 | 10.5024 | 87.83168 | 2083470 | 202407.6 | 72051.74 | 121.4324 | 408991672 | 191373990 | 97.08964 | NA | 21.36821 | 3155 | 228878 | 221.0 | 2.647571e+13 | 13502.11 | 69585382 | 97722 | NA | 3673264590 | 52.75165 | 21.36821 | 29239 | 3.937027e+12 | 107.43327 |
| 2012-04-01 | 852138 | 789542.0 | 550290.4 | 1388134 | 92013.41 | 52633.09 | 580 | 703033.3 | 215.2930 | 121442.5 | 4100547 | 5010929 | 1773.893 | 112970.3 | 19527.31 | 151309.5 | 3522192 | 59113.52 | 31688.49 | 31236.37 | 31427.60 | 31123.96 | 14159.99 | 82.59192 | NA | NA | NA | 66.98975 | 26.6 | NA | 2.871988e+14 | 1.246385e+14 | 1574.681 | 120.46350 | 77.42 | 61.1934 | 11.0870 | 84.06845 | 1406868 | 134531.8 | 63652.29 | 111.7223 | 344847316 | 161232070 | 82.73562 | NA | 35.50760 | 2319 | 196841 | 202.6 | 2.670166e+13 | 14575.28 | 67028317 | 95605 | NA | 3098189849 | 46.18602 | 35.50760 | 23982 | 3.864931e+12 | 98.47965 |
| 2012-05-01 | 919675 | 904690.6 | 639649.5 | 1960736 | 93279.24 | 52465.80 | 689 | 670334.7 | 209.5097 | 167643.9 | 5088029 | 5403375 | 1795.907 | 171028.7 | 21924.39 | 182269.8 | 3529123 | 53262.61 | 28144.86 | 47114.54 | 28830.46 | 32192.04 | 14491.28 | 94.27041 | NA | NA | NA | 71.02216 | 26.5 | NA | 2.906164e+14 | 1.265586e+14 | 1687.182 | 110.52174 | 77.66 | 61.5247 | 10.9950 | 87.93712 | 1233631 | 107659.3 | 71515.40 | 126.6002 | 411510051 | 198790367 | 90.79219 | NA | 27.95129 | 2507 | 226518 | 220.9 | 2.696925e+13 | 14565.48 | 68422194 | 54599 | NA | 2932225874 | 51.65681 | 27.95129 | 27637 | 3.986793e+12 | 104.51982 |
| 2012-06-01 | 906243 | 879219.3 | 620337.5 | 1956173 | 91314.75 | 52664.54 | 714 | 592504.2 | 185.8843 | 162433.1 | 4778664 | 4563431 | 1788.877 | 173377.4 | 23567.14 | 156605.5 | 2884610 | 51468.10 | 31688.85 | 40872.38 | 29003.39 | 34379.25 | 18788.05 | 92.06757 | NA | NA | NA | 72.57736 | 20.6 | NA | 2.939673e+14 | 1.237816e+14 | 1630.558 | 95.58905 | 77.72 | 62.3620 | 10.2437 | 87.82775 | 1997318 | 206133.8 | 71479.04 | 118.6786 | 390090495 | 172481442 | 94.30628 | NA | 27.94618 | 2643 | 238681 | 216.6 | 2.723038e+13 | 13434.11 | 68707263 | 54973 | NA | 2565482794 | 50.49887 | 27.94618 | 27984 | 3.944551e+12 | 106.11454 |
Declaración de Series Temporales
# Todas las series inician en Enero de 2012 y son mensuales (frequency = 12)
# 1. Ventas Minoristas (Target)
min_ts <- ts(data_col$MIN, start = c(2012, 1), frequency = 12)
# 2. Índice de Confianza del Consumidor
icc_ts <- ts(data_col$ICC, start = c(2012, 1), frequency = 12)
# 3. Cartera Bancaria
cart_ts <- ts(data_col$CART, start = c(2012, 1), frequency = 12)
# 4. Índice de Precios al Consumidor
ipc_ts <- ts(data_col$IPC, start = c(2012, 1), frequency = 12)
La descomposición de series de tiempo permite separar la tendencia, la estacionalidad y el componente irregular (ruido). Esto es fundamental para entender si el crecimiento de las ventas minoristas es estructural o simplemente un pico estacional (como la temporada navideña).
Aplicaremos la descomposición STL a nuestras variables para observar sus componentes.
# Función para descomponer y graficar
descomponer_variable <- function(serie_ts, nombre_var) {
stl_decomp <- stl(serie_ts, s.window = "periodic")
stl_df <- data.frame(
Time = rep(time(serie_ts), 4),
Value = c(stl_decomp$time.series[, "seasonal"],
stl_decomp$time.series[, "trend"],
stl_decomp$time.series[, "remainder"],
serie_ts),
Component = rep(c("Estacional", "Tendencia", "Residuo", "Serie Original"), each = length(serie_ts))
)
p <- ggplot(stl_df, aes(x = Time, y = Value, color = Component)) +
geom_line() +
facet_wrap(~Component, scales = "free_y", ncol = 1) +
theme_minimal() +
labs(title = paste("Descomposición STL:", nombre_var), x = "Tiempo", y = "Valor")
return(list(decomp = stl_decomp, plot = ggplotly(p)))
}
# Ejecutar para las 4 variables
res_min <- descomponer_variable(min_ts, "Ventas Minoristas (MIN)")
res_icc <- descomponer_variable(icc_ts, "Confianza del Consumidor (ICC)")
res_cart <- descomponer_variable(cart_ts, "Cartera Bancaria (CART)")
res_ipc <- descomponer_variable(ipc_ts, "Inflación (IPC)")
# Mostrar gráficos (ejemplo con MIN e ICC)
res_min$plot
res_icc$plot
La tendencia nos muestra la dirección de largo plazo del sector, eliminando el “ruido” estacional.
graficar_tendencia <- function(serie_ts, stl_obj, nombre_var) {
fechas <- seq.Date(from = as.Date("2012-01-01"), by = "month", length.out = length(serie_ts))
tendencia <- as.numeric(stl_obj$time.series[, "trend"])
p <- ggplot() +
geom_line(aes(x = fechas, y = as.numeric(serie_ts), color = "Original"), alpha = 0.4) +
geom_line(aes(x = fechas, y = tendencia, color = "Tendencia"), size = 1) +
scale_color_manual(values = c("Original" = "grey", "Tendencia" = "red")) +
labs(title = paste("Tendencia de Largo Plazo:", nombre_var), x = "Tiempo", y = "Valor") +
theme_minimal()
return(ggplotly(p))
}
graficar_tendencia(min_ts, res_min$decomp, "MIN")
graficar_tendencia(icc_ts, res_icc$decomp, "ICC")
Calculamos la variación porcentual a 12 meses para entender la dinámica de crecimiento de la tendencia.
calcular_tasa_anual <- function(serie_ts, stl_obj, nombre_var) {
tendencia <- stl_obj$time.series[, "trend"]
# Tasa sobre tendencia (limpia de estacionalidad)
tasa_tendencia <- (tendencia[13:length(tendencia)] / tendencia[1:(length(tendencia)-12)] - 1) * 100
fechas_corregidas <- seq(from = as.Date("2013-01-01"), by = "month", length.out = length(tasa_tendencia))
p <- ggplot() +
geom_line(aes(x = fechas_corregidas, y = as.numeric(tasa_tendencia)), color = "darkblue", size = 0.8) +
geom_hline(yintercept = 0, linetype = "dashed") +
labs(title = paste("Tasa de Crecimiento Anual de la Tendencia (%):", nombre_var),
x = "Tiempo", y = "% Variación Anual") +
theme_minimal()
return(ggplotly(p))
}
calcular_tasa_anual(min_ts, res_min$decomp, "MIN")
calcular_tasa_anual(cart_ts, res_cart$decomp, "CART")
Analizar la tasa de crecimiento anual ayuda a detectar cambios en el entorno económico que afectan el sector. Se pueden prever crisis o períodos de auge y prepararse para ellos.
El objetivo es construir un modelo que capture la estructura de las ventas minoristas para predecir su comportamiento en el corto plazo.
Utilizaremos el periodo 2012-2024 para entrenar el modelo y el año 2025 para validar su precisión. Esto nos permite evaluar qué tan bien el modelo predice los datos más recientes.
# Conjunto de entrenamiento: 2012-01 a 2024-12
train_min <- window(min_ts, end = c(2024, 12))
# Conjunto de prueba: 2025-01 a 2025-12
test_min <- window(min_ts, start = c(2025, 1))
Un requisito de los modelos ARIMA es que la serie sea estacionaria.
# Test de Dickey-Fuller Aumentado (ADF)
adf_min <- adf.test(train_min)
print(adf_min)
##
## Augmented Dickey-Fuller Test
##
## data: train_min
## Dickey-Fuller = -4.9415, Lag order = 5, p-value = 0.01
## alternative hypothesis: stationary
Observamos los correlogramas para identificar los posibles parámetros (p, d, q).
acf_plot <- ggAcf(train_min, lag.max = 6) + ggtitle("ACF - Ventas Minoristas (MIN)")
pacf_plot <- ggPacf(train_min, lag.max = 6) + ggtitle("PACF - Ventas Minoristas (MIN)")
ggplotly(acf_plot)
ggplotly(pacf_plot)
A partir de los correlogramas (ACF y PACF), se observa que la serie tiene una persistencia significativa. Identificamos los posibles parámetros iniciales para un modelo manual: - p (AR): El PACF muestra cortes o disminuciones después del primer o segundo rezago. - q (MA): El ACF también muestra una estructura que sugiere componentes de media móvil.
Siguiendo la instrucción, procederemos a estimar manualmente un modelo ARIMA(1,0,1) (p=1, d=0, q=1).
En esta sección estimamos el modelo de forma manual para contrastar su desempeño inicial antes de pasar al ajuste automático.
library(lmtest)
# Estimación manual ARIMA(1,0,1)
modelo_manual <- Arima(train_min, order = c(1,0,1))
summary(modelo_manual)
## Series: train_min
## ARIMA(1,0,1) with non-zero mean
##
## Coefficients:
## ar1 ma1 mean
## 0.9798 -0.6878 97.2768
## s.e. 0.0296 0.1575 12.4713
##
## sigma^2 = 163.6: log likelihood = -618.26
## AIC=1244.52 AICc=1244.78 BIC=1256.72
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 0.9098122 12.66793 8.442295 -0.6762557 8.65148 1.17435 0.1395705
# Evaluación de la significancia estadística de los coeficientes
coeftest(modelo_manual)
##
## z test of coefficients:
##
## Estimate Std. Error z value Pr(>|z|)
## ar1 0.979830 0.029565 33.1419 < 2.2e-16 ***
## ma1 -0.687750 0.157545 -4.3654 1.269e-05 ***
## intercept 97.276824 12.471282 7.8001 6.187e-15 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Es fundamental verificar si los residuos se comportan como ruido blanco para validar el ajuste.
checkresiduals(modelo_manual)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(1,0,1) with non-zero mean
## Q* = 238.33, df = 22, p-value < 2.2e-16
##
## Model df: 2. Total lags used: 24
Las gráficas de validación de residuos del modelo muestran un comportamiento invalido en general. En el gráfico superior, la serie de residuos oscila entre -25 y 25 con frecuentes grandes picos, lo que indica que el modelo no captura correctamente la tendencia. Por su parte, la función de autocorrelación (ACF) en la gráfica inferior izquierda evidencia que existen correlaciones significativas en los rezagos. Sin embargo, el histograma de la gráfica inferior derecha presenta una distribución aproximadamente normal, alineándose con el supuesto de normalidad esperado en un modelo SARIMA bien ajustado.
Evaluamos el desempeño del modelo manual en el periodo de prueba (2025), adaptando el código para comparar con los datos observados.
# Generar pronóstico manual para los 12 meses de 2025
manual_forecast_2025 <- forecast(modelo_manual, h = 12)
# Crear dataframe para gráfico interactivo
manual_forecast_data <- data.frame(
Tiempo = as.numeric(time(test_min)),
Pronostico = as.numeric(manual_forecast_2025$mean),
Observado = as.numeric(test_min)
)
# Graficar pronóstico manual vs observado
p_manual <- ggplot(manual_forecast_data, aes(x = Tiempo)) +
geom_line(aes(y = Pronostico, color = "Pronóstico Manual"), size = 1) +
geom_line(aes(y = Observado, color = "Observado"), size = 1) +
scale_color_manual(values = c("Pronóstico Manual" = "blue", "Observado" = "black")) +
labs(title = "Modelo Manual ARIMA(1,0,1): Pronóstico vs Observado (2025)",
x = "Tiempo", y = "Ventas Minoristas (MIN)") +
theme_minimal()
ggplotly(p_manual)
# Métricas de precisión del modelo manual
accuracy(manual_forecast_2025, test_min)
## ME RMSE MAE MPE MAPE MASE
## Training set 0.9098122 12.66793 8.442295 -0.6762557 8.651480 1.174350
## Test set 4.6931195 16.41734 11.758575 2.4908609 8.559947 1.635655
## ACF1 Theil's U
## Training set 0.1395705 NA
## Test set 0.4401955 1.494502
La gráfica evidencia que el modelo ARIMA manual (1,0,1) utilizado para pronosticar el año 2025 no logra ajustarse adecuadamente al comportamiento real de la serie, ya que presenta una dinámica prácticamente opuesta a la observada. Mientras el pronóstico generado por el modelo sugiere un decrecimiento en las ventas minoristas (MIN) a lo largo del periodo, los datos reales evidencian una tendencia de crecimiento sostenido durante ese mismo año. Esta discrepancia indica que el modelo no está capturando correctamente la estructura de la serie, por lo que sería necesario reconsiderar la especificación de sus parámetros o incorporar otros componentes que mejoren su capacidad predictiva.
Para un análisis más detallado, observamos cómo se comportó el modelo manual en los últimos tres meses del año de prueba.
# 1. Extraer los últimos 3 meses (Oct, Nov, Dic 2025)
# El pronóstico manual tiene 12 meses, los últimos 3 son el trimestre final
trimestre_final_pronostico <- tail(as.numeric(manual_forecast_2025$mean), 3)
trimestre_final_real <- tail(as.numeric(test_min), 3)
# 2. Crear tabla comparativa
tabla_trimestre <- data.frame(
Mes = c("Octubre", "Noviembre", "Diciembre"),
Real = trimestre_final_real,
Pronostico = trimestre_final_pronostico,
Error_Absoluto = abs(trimestre_final_real - trimestre_final_pronostico)
)
# Añadir columna de error porcentual para mejor interpretación
tabla_trimestre <- tabla_trimestre %>%
mutate(Error_Porcentual = (Error_Absoluto / Real) * 100)
# Mostrar la tabla
print(tabla_trimestre)
## Mes Real Pronostico Error_Absoluto Error_Porcentual
## 1 Octubre 131.7546 122.6604 9.094222 6.902394
## 2 Noviembre 140.7683 122.1484 18.619910 13.227347
## 3 Diciembre 168.2604 121.6467 46.613706 27.703309
# 3. Calcular métricas específicas para el trimestre
mae_trimestre <- mean(tabla_trimestre$Error_Absoluto)
rmse_trimestre <- sqrt(mean((tabla_trimestre$Real - tabla_trimestre$Pronostico)^2))
cat("\n--- Métricas del Último Trimestre 2025 ---\n")
##
## --- Métricas del Último Trimestre 2025 ---
cat("MAE Trimestral: ", round(mae_trimestre, 2), "\n")
## MAE Trimestral: 24.78
cat("RMSE Trimestral: ", round(rmse_trimestre, 2), "\n")
## RMSE Trimestral: 29.45
cat("MAPE Trimestral: ", round(mean(tabla_trimestre$Error_Porcentual), 2), "%\n")
## MAPE Trimestral: 15.94 %
Usaremos auto.arima para encontrar el modelo óptimo que
minimice el AIC. Dado que MIN tiene una estacionalidad marcada,
consideraremos un modelo SARIMA.
# Modelo automático (SARIMA)
modelo_auto <- auto.arima(train_min, seasonal = TRUE, stepwise = FALSE, approximation = FALSE)
summary(modelo_auto)
## Series: train_min
## ARIMA(3,0,0)(2,1,0)[12] with drift
##
## Coefficients:
## ar1 ar2 ar3 sar1 sar2 drift
## 0.8323 -0.3466 0.2917 -0.5160 -0.3539 0.3019
## s.e. 0.0804 0.1057 0.0819 0.0796 0.0777 0.0890
##
## sigma^2 = 28.32: log likelihood = -445
## AIC=904 AICc=904.82 BIC=924.78
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE
## Training set 0.02287847 5.005494 3.251035 -0.2660799 3.448214 0.4522293
## ACF1
## Training set -0.02283771
# Generar pronóstico para el periodo de prueba (2025)
pronostico_2025 <- forecast(modelo_auto, h = 12)
# Validación de residuos
checkresiduals(modelo_auto)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(3,0,0)(2,1,0)[12] with drift
## Q* = 28.878, df = 19, p-value = 0.06794
##
## Model df: 5. Total lags used: 24
Las gráficas de validación de residuos del modelo muestran un comportamiento adecuado en general. En el gráfico superior, la serie de residuos oscila alrededor de cero, lo que indica que el modelo captura correctamente la tendencia, aunque se observan picos marcados alrededor del año 2020 que podrían sugerir posibles cambios estructurales en los datos a causa de la pandemia. Por su parte, la función de autocorrelación (ACF) en la gráfica inferior izquierda evidencia que no existen correlaciones significativas en los rezagos, lo que respalda la independencia de los residuos. Finalmente, el histograma de la gráfica inferior derecha presenta una distribución aproximadamente normal, alineándose con el supuesto de normalidad esperado en un modelo SARIMA bien ajustado.
Comparamos las predicciones del modelo automático frente a lo que realmente ocurrió en 2025. Incluimos el intervalo de confianza del 95% para visualizar el margen de error esperado.
# 1. Preparar el dataframe de validación con intervalos de confianza
grafico_val_data <- data.frame(
Fecha = as.numeric(time(test_min)),
Real = as.numeric(test_min),
Pronostico = as.numeric(pronostico_2025$mean),
Inf_95 = as.numeric(pronostico_2025$lower[,2]), # Intervalo inferior al 95%
Sup_95 = as.numeric(pronostico_2025$upper[,2]) # Intervalo superior al 95%
)
# 2. Crear el gráfico avanzado con ggplot2
plot_valid <- ggplot(grafico_val_data, aes(x = Fecha)) +
# Área de incertidumbre (95%)
geom_ribbon(aes(ymin = Inf_95, ymax = Sup_95, fill = "Intervalo Confianza (95%)"), alpha = 0.2) +
# Línea de valor Real
geom_line(aes(y = Real, color = "Valor Real"), size = 1) +
# Línea de Pronóstico (Dashed para diferenciar)
geom_line(aes(y = Pronostico, color = "Pronóstico SARIMA"), size = 1, linetype = "dashed") +
# Puntos para mayor detalle
geom_point(aes(y = Real, color = "Valor Real"), size = 1.5) +
# Estética y Colores
scale_fill_manual(values = c("Intervalo Confianza (95%)" = "gray50")) +
scale_color_manual(values = c("Valor Real" = "black", "Pronóstico SARIMA" = "red")) +
labs(
title = "Validación Modelo Automático: Real vs Pronóstico (2025)",
subtitle = "El sombreado representa la incertidumbre estadística del modelo",
x = "Tiempo",
y = "Ventas Minoristas (MIN)",
color = "Referencia",
fill = ""
) +
theme_minimal() +
theme(legend.position = "bottom")
# 3. Convertir a interactivo
ggplotly(plot_valid)
# Métricas de precisión
accuracy(pronostico_2025, test_min)
## ME RMSE MAE MPE MAPE MASE
## Training set 0.02287847 5.005494 3.251035 -0.2660799 3.448214 0.4522293
## Test set 5.48388571 6.816792 5.483886 4.0165773 4.016577 0.7628260
## ACF1 Theil's U
## Training set -0.02283771 NA
## Test set 0.21968419 0.6404688
La gráfica anterior evidencia que el pronóstico sigue de cerca la tendencia real a lo largo del 2025, capturando adecuadamente tanto las variaciones como la dirección general de la serie. Además, el área gris representa el intervalo de confianza del 95%, dentro del cual se encuentran la totalidad de los valores observados, lo que indica un buen nivel de precisión del modelo. En conjunto, estos resultados sugieren que el modelo es bastante acertado y puede ser utilizado de manera confiable para predecir el comportamiento de las ventas minoristas en el futuro cercano.
Para la proyección final, utilizamos toda la serie histórica disponible (hasta diciembre 2025). Siguiendo las recomendaciones técnicas, ajustaremos un modelo SARIMA robusto evitando aproximaciones para garantizar la máxima precisión.
# 1. Re-ajustar modelo con toda la serie usando búsqueda exhaustiva
modelo_final <- auto.arima(min_ts, seasonal = TRUE, stepwise = FALSE, approximation = FALSE)
# 2. Pronosticar 1 mes (Enero 2026)
pronostico_final <- forecast(modelo_final, h = 1)
# 3. Extraer valores clave
valor_ene_2026 <- as.numeric(pronostico_final$mean[1])
lim_inf_95 <- pronostico_final$lower[1, 2] # Límite inferior al 95%
lim_sup_95 <- pronostico_final$upper[1, 2] # Límite superior al 95%
# 4. Visualización Profesional
autoplot(window(min_ts, start=c(2024,1))) +
autolayer(pronostico_final, series="Pronóstico Ene 2026", PI = TRUE) +
geom_point(aes(x = 2026, y = valor_ene_2026), color = "red", size = 2) +
labs(title = "Pronóstico de Ventas Minoristas: Enero 2026",
subtitle = paste("Valor estimado:", round(valor_ene_2026, 2),
" | Intervalo (95%): [", round(lim_inf_95, 2), "-", round(lim_sup_95, 2), "]"),
x = "Meses / Año",
y = "Índice de Ventas (MIN)",
caption = "Fuente: Elaboración propia basada en modelo SARIMA robusto") +
theme_minimal() +
theme(legend.position = "bottom")
print(paste("El pronóstico central para Enero 2026 es:", round(valor_ene_2026, 2)))
## [1] "El pronóstico central para Enero 2026 es: 131.3"
La gráfica anterior presenta el comportamiento histórico real de las ventas minoristas (MIN) junto con el pronóstico para enero de 2026 estimado mediante un modelo SARIMA, el cual se sitúa en aproximadamente 132.21. Se observa que la serie ha seguido una tendencia general al alza a lo largo del tiempo, con algunas fluctuaciones intermedias, pero manteniendo un crecimiento sostenido. El valor proyectado se alinea coherentemente con esta dinámica, reflejando la continuidad de la tendencia positiva observada en los datos históricos. En este sentido, el pronóstico es consistente con una tasa de crecimiento anual positiva, lo que respalda la idea de que las ventas minoristas continuarán expandiéndose en el corto plazo.
Basado en el análisis de señales y el rigor estadístico del modelo SARIMA para las Ventas Minoristas (MIN), se presentan las siguientes conclusiones: