Instalar/Cargar librerias necesarias para el análisis

#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(timetk)   #timetk simplifica y acelera el análisis exploratorio, visualización, y preparación de datos temporales para modelado. Es ideal para quienes trabajan con series temporales en un flujo de trabajo "tidy" y buscan integrar análisis visuales, detección de patrones y forecasting en un solo paquete.
library(ggcorrplot)
library(kableExtra)

Cargar base de datos

library(readxl)
data_col <- read_excel("Base Caso2.xlsx", 
    col_types = c("date", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric", "numeric"))

Contexto del sector y empresa

En la actualidad, el sector automotriz colombiano atraviesa un proceso de transformación marcado por cambios económicos, tecnológicos y en las preferencias de los consumidores. El análisis del comportamiento del mercado durante los últimos cinco años evidencia un escenario de alta volatilidad: después de la recuperación registrada en 2021 y 2022, el sector experimentó una contracción significativa en 2023, seguida de una recuperación durante 2024 y 2025. En particular, durante 2023 las ventas de vehículos nuevos disminuyeron cerca de un 29% frente al año anterior (Fenalco-ANDI, 2024), comportamiento asociado principalmente con factores como el incremento de las tasas de interés, la inflación, las mayores dificultades de acceso al crédito y la reducción de la capacidad de compra y confianza de los consumidores.

A partir de 2024 se observa una recuperación progresiva del mercado, que se consolidó durante 2025 con un crecimiento cercano al 26,5% en las ventas de vehículos nuevos (Fenalco-ANDI, 2025). Este comportamiento nacional se refleja de forma consistente en los datos regionales del Valle del Cauca analizados en este informe: las ventas de vehículos nuevos en el departamento cayeron 34,9% en 2023, se recuperaron 14,5% en 2024 y crecieron 24,7% en 2025, cifras alineadas con la tendencia nacional, aunque con una contracción más pronunciada en 2023, lo que sugiere una mayor sensibilidad del mercado regional al ciclo económico.

Sin embargo, la recuperación del sector no se limita al incremento en el número de unidades comercializadas, sino que también refleja un cambio en la composición de la demanda. Durante este período se ha presentado un crecimiento significativo en la comercialización de vehículos híbridos y eléctricos, evidenciando una transición hacia tecnologías de movilidad más eficientes y con menores niveles de emisiones. Esta transformación plantea nuevos desafíos para las empresas del sector, que deben adaptar sus portafolios y estrategias comerciales para responder a consumidores cada vez más interesados en aspectos como la eficiencia, la tecnología, la seguridad, la conectividad y la sostenibilidad.

Fanalca S.A.S, empresa colombiana con sede en Yumbo, Valle del Cauca, es el distribuidor oficial de los automóviles de la marca Honda en Colombia desde 1991. La compañía presenta una estrategia de venta diferenciada frente a sus competidores, enfocándose principalmente en vehículos tipo SUV, automóviles y vehículos familiares, ofreciendo en estos cualidades como confiabilidad, tecnología, diseño y calidad. Al estar ubicada directamente en el Valle del Cauca, la evolución del mercado automotor regional resulta especialmente relevante para su operación comercial y de distribución en el departamento.

Honda se encuentra por debajo de las principales marcas que controlan el mercado colombiano, como Toyota, Renault, Chevrolet, Kia, Mazda y Hyundai; sin embargo, se evidencia un posicionamiento enfocado en vehículos tipo SUV. Por esto, se considera que este análisis permite a Fanalca establecer estrategias orientadas a mantenerse dentro del mercado y potencializar su participación en las unidades vendidas de automóviles Honda.

Justificación de las tres variables

Para este análisis se escogieron tres variables: las ventas minoristas, el Índice de Confianza del Consumidor y las ventas de vehículos nuevos en el Valle del Cauca. Se eligieron juntas porque cuentan con la siguiente relación; primero cómo está el consumo de los hogares en general, luego qué tan optimistas o preocupados están los colombianos con la economía, y finalmente cómo se traduce todo eso en la compra de carros, que es uno de los negocios de Fanalca como distribuidor de Autos Honda.

Las ventas minoristas muestran, en términos generales, qué tanto están comprando los hogares colombianos. Es un buen punto de partida porque si la personas está comprando más en general, es probable que también se apertura la posibilidad de comprar carro.

El Índice de Confianza del Consumidor mide qué tan optimistas o preocupados están los colombianos frente a su situación económica. Cuando las personas se siente segura de su futuro, tiende a gastar más y a animarse a comprar cosas costosas, como un carro. Cuando hay incertidumbre, la gente prefiere ahorrar y aplazar esas compras. Por eso consideramos que este indicador podría avisar con anticipación si las ventas de carros van a subir o bajar,

Por último, se escogió la variable de ventas de vehículos nuevos en el Valle del Cauca porque es exactamente uno de los mercados en el que trabaja Fanalca como distribuidor de autos Honda. Esta variable nos permite ver cómo le está yendo al mercado local de carros, y compararlo con lo que muestran las otras dos variables: el consumo general y la confianza de la personas.

Variable 1

# Convertir/declarar variable 1=VEH_V en serie de tiempo mensual
variable1_ts <- ts(data_col$VEH_V, start = c(2012, 1), frequency = 12)

Variable 2

# Convertir/declarar el MIN en serie de tiempo  mensual
variable2_ts <- ts(data_col$MIN, start = c(2012, 1), frequency = 12)

Variable 3

# Convertir/declarar el indice  de confianza del consumidor en serie de tiempo mensual
variable3_ts <- ts(data_col$ICC, start = c(2012, 1), frequency = 12)

Extracción de señales

Gráfico inicial de la variable 1 en niveles -Original

library(ggplot2)
library(plotly)

# Convertir la serie temporal a un vector numérico para lograr graficar con ggplot2
data_col$variable1 <- as.numeric(variable1_ts)

# Crear el gráfico
grafico_serie <- ggplot(data_col, aes(x = seq.Date(from = as.Date("2012-01-01"), by = "month", length.out = nrow(data_col)), 
                                      y = variable1)) +
  geom_line(color = "grey", linewidth = 0.4) +  # Cambiado 'size' por 'linewidth'
  geom_point(color = "black", size = 0.1) +
  ggtitle("Figura 1: Variable 1 - Serie original") +
  xlab("Tiempo") +
  ylab("Unidad Variable 1") +
  theme_minimal()

ggplotly(grafico_serie)

Extracción señales variable 1

# Cargar librerías necesarias
library(ggplot2)
library(plotly)

# Descomposición de la serie temporal
stl_decomp_var1 <- stl(variable1_ts, s.window = "periodic")

# Convertir la descomposición a un data frame para graficar con ggplot2
stl_df_var1 <- data.frame(
  Time = rep(zoo::as.Date(time(variable1_ts)), 4),  # Tiempo repetido para cada componente (son 4 componentes)
  Value = c(stl_decomp_var1$time.series[, "seasonal"], 
            stl_decomp_var1$time.series[, "trend"], 
            stl_decomp_var1$time.series[, "remainder"], 
            variable1_ts),
  Component = rep(c("Estacional", "Tendencia", "Residuo", "Serie Original"), each = length(variable1_ts))
)

# Crear gráfico con ggplot2
p <- ggplot(stl_df_var1, aes(x = Time, y = Value, color = Component)) +
  geom_line() +
  facet_wrap(~Component, scales = "free_y", ncol = 1) + 
  theme_minimal() +
  labs(title = "Figura 2. Descomposición temporal de la variable 1",
       x = "Tiempo",
       y = "Valor")

# Convertir a gráfico interactivo con plotly
ggplotly(p)

Interpretación Figura 2

Teniendo en cuenta la información de los graficos anteriores, la gráfica de tendencia muestra que las ventas de carros nuevos en el Valle cayeron durante 2020, esto debia al impacto de la pandemia en la economía. Pero el dato más relevante es que el punto más bajo de toda la historia analizada (2012-2025) no fue en pandemia, sino en octubre de 2023, un nivel incluso peor que el de 2020. Esto coincide con el momento en que las ventas de carros nuevos en Colombia cayeron cerca de un 29% en todo el país, por las altas tasas de interés y las dificultades para acceder a créditos, lo cual golpeó fuerte a este sector porque la mayoría de las personas en Colombia realizan la compra de carro, financiandolo. Además, se ve un patrón que se repite cada año; las ventas suben mucho hacia fin de año (especialmente en diciembre) y bajan en los primeros meses del año siguiente, siendo esta una constante en toda la serie.

Extracción señales variable 2

# Cargar librerías necesarias
library(ggplot2)
library(plotly)

# Descomposición de la serie temporal
stl_decomp_var2 <- stl(variable2_ts, s.window = "periodic")

# Convertir la descomposición a un data frame para graficar con ggplot2
stl_df_var2 <- data.frame(
  Time = rep(zoo::as.Date(time(variable1_ts)), 4),  # Tiempo repetido para cada componente
  Value = c(stl_decomp_var2$time.series[, "seasonal"], 
            stl_decomp_var2$time.series[, "trend"], 
            stl_decomp_var2$time.series[, "remainder"], 
            variable2_ts),
  Component = rep(c("Estacional", "Tendencia", "Residuo", "Serie Original"), each = length(variable2_ts))
)

# Crear gráfico con ggplot2
p <- ggplot(stl_df_var2, aes(x = Time, y = Value, color = Component)) +
  geom_line() +
  facet_wrap(~Component, scales = "free_y", ncol = 1) + 
  theme_minimal() +
  labs(title = "Figura 3. Descomposición temporal de la variable 2",
       x = "Tiempo",
       y = "Valor")

# Convertir a gráfico interactivo con plotly
ggplotly(p)

Interpretación Figura 3

En cuanto a la variable 2. La tendencia de las ventas minoristas muestra un crecimiento constante durante todo el período analizado, con leves desaceleraciones en los mismos momentos críticos que afectaron a la venta de los carros: la pandemia y la crisis de 2023. Sin embargo, a diferencia de las ventas de vehículos, que sí sufrieron caídas fuertes en esos períodos, las ventas minoristas en general apenas se ve afectado y sigue una tendencia mayormente al alza. Esto es relevante, las personas sigue comprando lo básico incluso en crisis, mientras que comprar un carro, es de las primeras decisiones que se aplazan cuando suben las tasas de interés o hay incertidumbre económica.

En cuanto al patrón que se repite cada año, las ventas minoristas suben fuerte en diciembre y bajan a su punto más bajo en febrero, siendo este un comportamiento estacional muy marcado y constante en toda la serie.

Extracción señales variable 3

# Cargar librerías necesarias
library(ggplot2)
library(plotly)

# Descomposición de la serie temporal
stl_decomp_var3 <- stl(variable3_ts, s.window = "periodic")

# Convertir la descomposición a un data frame para graficar con ggplot2
stl_df_var3 <- data.frame(
  Time =  rep(zoo::as.Date(time(variable1_ts)), 4),  # Tiempo repetido para cada componente
  Value = c(stl_decomp_var3$time.series[, "seasonal"], 
            stl_decomp_var3$time.series[, "trend"], 
            stl_decomp_var3$time.series[, "remainder"], 
            variable3_ts),
  Component = rep(c("Estacional", "Tendencia", "Residuo", "Serie Original"), each = length(variable3_ts))
)

# Crear gráfico con ggplot2
p <- ggplot(stl_df_var3, aes(x = Time, y = Value, color = Component)) +
  geom_line() +
  facet_wrap(~Component, scales = "free_y", ncol = 1) + 
  theme_minimal() +
  labs(title = "Figura 4. Descomposición temporal de la variable 3",
       x = "Tiempo",
       y = "Valor")

# Convertir a gráfico interactivo con plotly
ggplotly(p)

Interpretación Figura 4

El Índice de Confianza del Consumidor muestra un comportamiento volátil, sin una tendencia de largo plazo clara como sí tienen las otras dos variables, y con un sesgo hacia el terreno negativo durante buena parte del período. El punto más bajo de toda la serie histórica se ubica en marzo de 2023, coincidiendo justamente con la crisis que golpeó también a las ventas de vehículos. Desde entonces se observa una recuperación sostenida: aunque el indicador se mantuvo en negativo por varios años, apenas hasta mediados de 2025 logra pasar a terreno positivo, lo que sugiere que la confianza de los consumidores está mejorando, aunque de forma lenta.

En cuanto al patrón que se repite cada año, aquí la estacionalidad es más suave que en las otras dos variables: hay una leve mejora en la confianza hacia mitad y fin de año y una leve caída en los primeros meses, pero sin picos tan marcados como los que se ven en las ventas de vehículos o ventas minoristas.

Después de la descomposición temporal de cada variable, se extrae la variable ajustada por estacionalidad para graficarla junto con la serie original:

Se crea la variable1 ajustada por estacionalidad

# Extraer los componentes de la descomposición
variable1_sa <- variable1_ts - stl_decomp_var1$time.series[, "seasonal"]

Se crea la variable2 ajustada por estacionalidad

# Extraer los componentes de la descomposición
variable2_sa <- variable2_ts - stl_decomp_var2$time.series[, "seasonal"]

Se crea la variable3 ajustada por estacionalidad

# Extraer los componentes de la descomposición
variable3_sa <- variable3_ts - stl_decomp_var3$time.series[, "seasonal"]

Ahora si se puede graficar las series originales versus la ajustada por estacionalidad

Gráfico serie original VS ajustada Variable 1

# Crear vector de fechas correctamente alineado con la serie
fechas_var1 <- seq.Date(from = as.Date("2012-01-01"), by = "month", length.out = length(variable1_ts))

# Gráfico mejorado con fechas en el eje X
grafico_ajustada_var1 <- ggplot() +
  geom_line(aes(x = fechas_var1, y = variable1_ts), color = "grey", size = 0.5, linetype = "solid", name = "Serie Original") +
  geom_line(aes(x = fechas_var1, y = variable1_sa), color = "black", size = 0.6, linetype = "solid", name = "Serie Ajustada") +
  ggtitle("Figura 5. Variable 1:Serie Original vs Serie Ajustada por Estacionalidad") +
  xlab("Tiempo") +
  ylab("Unidad de medida variable 1") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotar etiquetas para mejor visualización

# Convertir a gráfico interactivo
ggplotly(grafico_ajustada_var1)

Interpretación Figura 5

La serie ajustada por estacionalidad de la variable 1, permite observar el comportamiento real de las ventas de vehículos, eliminando el efecto recurrente de los picos de diciembre y las caídas de inicio de año. Se confirma que la fuerte caída de 2020 no responde a un patrón estacional sino a un choque real que fue la pandemia, mientras que los picos de la serie original en diciembre de cada año corresponden en gran parte al efecto estacional propio de fin de año, más que a un cambio sostenido en el mercado

Gráfico serie original VS ajustada Variable 2

# Crear vector de fechas correctamente alineado con la serie
fechas_var2 <- seq.Date(from = as.Date("2012-01-01"), by = "month", length.out = length(variable2_ts))

# Gráfico mejorado con fechas en el eje X
grafico_ajustada_var2 <- ggplot() +
  geom_line(aes(x = fechas_var2, y = variable2_ts), color = "grey", size = 0.5, linetype = "solid", name = "Serie Original") +
  geom_line(aes(x = fechas_var2, y = variable2_sa), color = "black", size = 0.6, linetype = "solid", name = "Serie Ajustada") +
  ggtitle("Figura 6. Variable 2:Serie Original vs Serie Ajustada por Estacionalidad") +
  xlab("Tiempo") +
  ylab("Unidad de medida variable 2") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotar etiquetas para mejor visualización

# Convertir a gráfico interactivo
ggplotly(grafico_ajustada_var2)

Interpretación Figura 6

En cuanto a la variable 2. ventas minoristas, la diferencia entre la serie original y la ajustada es aún más marcada: los picos de diciembre en la serie original son muy pronunciados y se repiten sistemáticamente cada año, mientras que la serie ajustada muestra una tendencia de crecimiento sostenido y mucho más suave. Esto confirma que el fuerte aumento de fin de año es un patrón estacional recurrente y predecible, no un cambio real en el nivel del consumo. También se observa que, a diferencia de VEH_V, la caída de 2020 fue más moderada y de recuperación más rápida, reforzando que las ventas minorista en general es menos sensible a los impactos económicos que el mercado de vehículos.

Gráfico serie original VS ajustada Variable 3

# Crear vector de fechas correctamente alineado con la serie
fechas_var3 <- seq.Date(from = as.Date("2012-01-01"), by = "month", length.out = length(variable3_ts))

# Gráfico mejorado con fechas en el eje X
grafico_ajustada_var3 <- ggplot() +
  geom_line(aes(x = fechas_var3, y = variable3_ts), color = "grey", size = 0.5, linetype = "solid", name = "Serie Original") +
  geom_line(aes(x = fechas_var3, y = variable3_sa), color = "black", size = 0.6, linetype = "solid", name = "Serie Ajustada") +
  ggtitle("Figura 7. Variable 3:Serie Original vs Serie Ajustada por Estacionalidad") +
  xlab("Tiempo") +
  ylab("Unidad de medida variable 3") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotar etiquetas para mejor visualización

# Convertir a gráfico interactivo
ggplotly(grafico_ajustada_var3)

Interpretación Figura 7

En cuanto a la variable 3. Índice de Confianza del Consumidor, la serie original y la ajustada son casi idénticas, lo que confirma que su componente estacional es mucho más débil que en las otras dos variables. El comportamiento de esta variable está dominado por impactos de fondo, más que por un patrón que se repita cada año.

Ahora graficamos serie original vs tendencia

Primero se debe obtener la tendencia de cada variable y luego graficarla

Tendencia Variable 1

library(ggplot2)
library(plotly)

# Convertir la serie a un vector numérico
variable1_vec <- as.numeric(variable1_ts)
tendencia_var1 <- as.numeric(stl_decomp_var1$time.series[, "trend"])

# Asegurar que 'fechas' tenga la misma longitud
fechas <- seq.Date(from = as.Date("2012-01-01"), by = "month", length.out = length(variable1_ts))

# Gráfico interactivo de la serie original vs tendencia
grafico_tendencia_var1 <- ggplot() +
  geom_line(aes(x = fechas, y = variable1_vec, color = "Serie Original"), size = 0.7, linetype = "solid") +
  geom_line(aes(x = fechas, y = tendencia_var1, color = "Tendencia"), size = 0.8, linetype = "solid") +
  scale_color_manual(values = c("Serie Original" = "grey", "Tendencia" = "black")) +
  ggtitle("Figura 8. Variable 1: Serie Original vs Tendencia") +
  xlab("Tiempo") +
  ylab("Unidad de medida Variable 1") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotar etiquetas del eje X

# Convertir a gráfico interactivo con plotly
ggplotly(grafico_tendencia_var1)

Interpretación Figura 8

La línea de tendencia de la variable 1, confirma con claridad los hallazgos previos; un nivel relativamente estable hasta 2019, una caída fuerte en 2020 por la pandemia, una recuperación parcial en 2021-2022, y una segunda caida aún más fuerte en el 2023, siendo este el más bajo de toda la serie, seguido de una recuperación sostenida hasta 2025.

Tendencia Variable 2

library(ggplot2)
library(plotly)

# Convertir la serie a un vector numérico
variable2_vec <- as.numeric(variable2_ts)
tendencia_var2 <- as.numeric(stl_decomp_var2$time.series[, "trend"])

# Asegurar que 'fechas' tenga la misma longitud
fechas <- seq.Date(from = as.Date("2012-01-01"), by = "month", length.out = length(variable2_ts))

# Gráfico interactivo de la serie original vs tendencia
grafico_tendencia_var2 <- ggplot() +
  geom_line(aes(x = fechas, y = variable2_vec, color = "Serie Original"), size = 0.7, linetype = "solid") +
  geom_line(aes(x = fechas, y = tendencia_var2, color = "Tendencia"), size = 0.8, linetype = "solid") +
  scale_color_manual(values = c("Serie Original" = "grey", "Tendencia" = "black")) +
  ggtitle("Figura 9. Variable 2: Serie Original vs Tendencia") +
  xlab("Tiempo") +
  ylab("Unidad de medida Variable 2") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotar etiquetas del eje X

# Convertir a gráfico interactivo con plotly
ggplotly(grafico_tendencia_var2)

Interpretación Figura 9

En cuanto a la tendencia de la variable 2. ventas minoristas es de crecimiento sostenido durante todo el período, con una leve desaceleración en 2020 y otra más suave alrededor de 2023, pero sin caídas fuertes como la Venta de Vehiculos nuevos del Valle. Esto confirma que las ventas minorista en general es mucho más resiliente ante los impactos económicos que el mercado de vehículos.

Tendencia Variable 3

library(ggplot2)
library(plotly)

# Convertir la serie a un vector numérico
variable3_vec <- as.numeric(variable3_ts)
tendencia_var3 <- as.numeric(stl_decomp_var3$time.series[, "trend"])

# Asegurar que 'fechas' tenga la misma longitud
fechas <- seq.Date(from = as.Date("2012-01-01"), by = "month", length.out = length(variable3_ts))

# Gráfico interactivo de la serie original vs tendencia
grafico_tendencia_var3 <- ggplot() +
  geom_line(aes(x = fechas, y = variable3_vec, color = "Serie Original"), size = 0.7, linetype = "solid") +
  geom_line(aes(x = fechas, y = tendencia_var3, color = "Tendencia"), size = 0.8, linetype = "solid") +
  scale_color_manual(values = c("Serie Original" = "grey", "Tendencia" = "black")) +
  ggtitle("Figura 10. Variable 3: Serie Original vs Tendencia") +
  xlab("Tiempo") +
  ylab("Unidad de medida Variable 3") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotar etiquetas del eje X

# Convertir a gráfico interactivo con plotly
ggplotly(grafico_tendencia_var3)

Interpretación Figura 10

La tendencia de la variable 3.ICC no muestra una dirección de largo plazo clara, sino ciclos de deterioro y recuperación: una caída sostenida desde 2012 hasta 2017, una leve mejora hacia 2018, y luego nuevas caidas en 2020 y 2023, siendo la ultima caida la más profunda, seguidos de una recuperación reciente que apenas en 2025 empieza a acercarse a terreno positivo.

Ahora calculamos la tasa de crecimiento de la serie original vs tendencia:

Tasa de crecimiento de la serie de tendencia y original para la variable 1

#Cálculo de la tasa de crecimiento anual correctamente alineada
tasa_crecimiento_var1 <- (variable1_ts[(13:length(variable1_ts))] / variable1_ts[1:(length(variable1_ts) - 12)] - 1) * 100
tasa_tendencia_var1 <- (tendencia_var1[(13:length(tendencia_var1))] / tendencia_var1[1:(length(tendencia_var1) - 12)] - 1) * 100

# Crear vector de fechas corregido, es decir que inicie desde enero 2013
fechas_corregidas_var1 <- seq(from = as.Date("2013-01-01"), by = "month", length.out = length(tasa_crecimiento_var1))

# Verificar longitudes
print(length(fechas_corregidas_var1))
## [1] 156
print(length(tasa_crecimiento_var1))
## [1] 156
print(length(tasa_tendencia_var1))
## [1] 156

*Gráfico variable original y tendencia variable 1: tasa de crecimiento anual**

library(ggplot2)
library(plotly)

grafico_crecimiento_var1 <- ggplot() +
  geom_line(aes(x = fechas_corregidas_var1, y = tasa_crecimiento_var1), color = "grey", size = 0.7) +
  geom_line(aes(x = fechas_corregidas_var1, y = tasa_tendencia_var1), color = "black", size = 0.8, linetype = "dashed") +
  ggtitle("Figura 11. Variable1: Tasa de crecimiento anual % de la serie Original y la tendencia") +
  xlab("Tiempo") +
  ylab("% de Crecimiento Anual") +
  theme_minimal() +
  coord_cartesian(ylim = c(-100, 100))  # <- ajusta este rango después de revisar tus datos

ggplotly(grafico_crecimiento_var1)

Interpretación Figura 11

La tasa de crecimiento interanual de la variable 1, confirma el patrón de alta volatilidad del sector: caídas fuertes en 2020 y nuevamente en el 2023, adicionalmente se evidencia un aumento marcado posterior al 2020 y desde la caida del 2023, la tendencia de crecimiento se mantiene positiva y estable alrededor del 20-30%, confirmando la recuperación reciente del mercado.

Ahora calculamos la tasa de crecimiento de la serie original vs tendencia: variable 2

#Cálculo de la tasa de crecimiento anual correctamente alineada
tasa_crecimiento_var2 <- (variable2_ts[(13:length(variable2_ts))] / variable2_ts[1:(length(variable2_ts) - 12)] - 1) * 100
tasa_tendencia_var2 <- (tendencia_var2[(13:length(tendencia_var2))] / tendencia_var2[1:(length(tendencia_var2) - 12)] - 1) * 100

# Crear vector de fechas corregido
fechas_corregidas_var2 <- seq(from = as.Date("2013-01-01"), by = "month", length.out = length(tasa_crecimiento_var2))

# Verificar longitudes
print(length(fechas_corregidas_var2))
## [1] 156
print(length(tasa_crecimiento_var2))
## [1] 156
print(length(tasa_tendencia_var2))
## [1] 156
# Gráfico de la tasa de crecimiento anual variable 2
grafico_crecimiento_var2 <- ggplot() +
  geom_line(aes(x = fechas_corregidas_var2, y = tasa_crecimiento_var2), color = "grey", size = 0.7) +
  geom_line(aes(x = fechas_corregidas_var2, y = tasa_tendencia_var2), color = "black", size = 0.8, linetype = "dashed") +
  ggtitle("Figura 12. Variable2: Tasa de crecimiento anual % de la serie Original y la Tendencia") +
  xlab("Tiempo") +
  ylab("% de Crecimiento Anual") +
  theme_minimal()

# Convertir a gráfico interactivo
ggplotly(grafico_crecimiento_var2)

Interpretación Figura 12

La tasa de crecimiento de MIN muestra fluctuaciones mucho más moderadas que VEH_V, caídas leves en 2020 y 2023, y un aumento despues de pandemia en el 2020 menos extremo (frente al crecimiento de la venta de vehiculos nuevos en el valle). Desde 2024 la tendencia se estabiliza en un crecimiento positivo de alrededor del 10%, reforzando que la ventas minorista en general es una variable más estable y menos volátil que las ventas de vehículos.

Ahora calculamos la tasa de crecimiento de la serie original vs tendencia: variable 3

#Cálculo de la tasa de crecimiento anual correctamente alineada
tasa_crecimiento_var3 <- (variable3_ts[(13:length(variable3_ts))] / variable3_ts[1:(length(variable3_ts) - 12)] - 1) * 100
tasa_tendencia_var3 <- (tendencia_var3[(13:length(tendencia_var3))] / tendencia_var3[1:(length(tendencia_var3) - 12)] - 1) * 100

# Crear vector de fechas corregido
fechas_corregidas_var3 <- seq(from = as.Date("2013-01-01"), by = "month", length.out = length(tasa_crecimiento_var3))

# Verificar longitudes
print(length(fechas_corregidas_var3))
## [1] 156
print(length(tasa_crecimiento_var3))
## [1] 156
print(length(tasa_tendencia_var3))
## [1] 156
# Diferencia interanual en puntos (no porcentaje) para el ICC
diferencia_var3 <- variable3_ts[(13:length(variable3_ts))] - variable3_ts[1:(length(variable3_ts) - 12)]
diferencia_tendencia_var3 <- tendencia_var3[(13:length(tendencia_var3))] - tendencia_var3[1:(length(tendencia_var3) - 12)]

fechas_corregidas_var3 <- seq(from = as.Date("2013-01-01"), by = "month", 
                                length.out = length(diferencia_var3))

# Gráfico de la diferencia interanual en puntos - variable 3 (ICC)
grafico_diferencia_var3 <- ggplot() +
  geom_hline(yintercept = 0, color = "grey70", linetype = "solid", size = 0.5) +
  geom_line(aes(x = fechas_corregidas_var3, y = diferencia_var3), 
            color = "grey", size = 0.7) +
  geom_line(aes(x = fechas_corregidas_var3, y = diferencia_tendencia_var3), 
            color = "black", size = 0.8, linetype = "dashed") +
  ggtitle("Figura 13. Variable3: Diferencia interanual en puntos del ICC y la Tendencia") +
  xlab("Tiempo") +
  ylab("Diferencia en puntos (año actual - año anterior)") +
  theme_minimal()

ggplotly(grafico_diferencia_var3)

Interpretación Figura 13

En cuanto la variable 3. ICC, se expreso en puntos y se evidencia caídas marcadas alrededor de 2016 y 2020 (donde la confianza empeoró más de 20-40 puntos frente al año anterior), seguidas de recuperaciones hacia 2018 y 2021. El período más reciente (2023-2025) muestra una tendencia de mejora sostenida, con variaciones interanuales positivas que se acercan a los 20 puntos hacia el final de la serie, confirmando la recuperación de la confianza del consumidor identificada en los gráficos anteriores.

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.

Modelo ARIMA

División en conjunto de entrenamiento y prueba para la variable 1 que es la elegida para pronosticar

El código siguiente divide una serie temporal (variable1_ts) en dos subconjuntos:

Conjunto de entrenamiento (train): Datos desde enero de 2012 hasta septiembre de 2025. Conjunto de prueba (test): Datos desde octubre de 2025 hasta diciembre de 2025.

Esto se hace para evaluar el desempeño de modelos de predicción en datos no vistos.

# Esta división idealmente podria se 80%-70% de los datos para entrenamiento y 20%-30% para prueba o test

# En este ejemplo el conjunto de entrenamiento es: Enero 2012-Septiembre 2025 y  el conjunto de prueba o test: octubre 2025-diciembre 2025 

train_size <- length(variable1_ts) - 3 # Se deja fuera los últimos 3 valores para usarlos como set de prueba.
train_ts <- window(variable1_ts, end = c(2025, 9))  # Entrenamiento hasta septiembre 2025
test_ts <- window(variable1_ts, start = c(2025, 10))  # Prueba inicia desde oct2025

Modelo ARIMA automático normal (sin tener en cuenta el factor estacional)

Identificación automática del modelo ARIMA

library(forecast)

# Ajustar un modelo ARIMA automático sin estacionalidad, por eso se pone seasonal=FALSE
auto_arima_model_no_seasonal <- auto.arima(train_ts, seasonal = FALSE)

# Mostrar el modelo seleccionado
summary(auto_arima_model_no_seasonal)
## Series: train_ts 
## ARIMA(0,1,2) 
## 
## Coefficients:
##           ma1      ma2
##       -0.4636  -0.2689
## s.e.   0.0807   0.0956
## 
## sigma^2 = 142585:  log likelihood = -1205.18
## AIC=2416.37   AICc=2416.52   BIC=2425.67
## 
## Training set error measures:
##                     ME     RMSE      MAE       MPE     MAPE      MASE
## Training set -13.43009 374.1563 270.3888 -265.9302 276.4697 0.7077997
##                      ACF1
## Training set -0.002894499

Estimación del modelo identificado automatico y validación de Significancia de coeficientes

library(lmtest)

# Evaluar la significancia estadística de los coeficientes del modelo ARIMA
coeftest(auto_arima_model_no_seasonal)
## 
## z test of coefficients:
## 
##      Estimate Std. Error z value  Pr(>|z|)    
## ma1 -0.463565   0.080660 -5.7471 9.076e-09 ***
## ma2 -0.268911   0.095604 -2.8128  0.004912 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Ajuste del modelo ARIMA(0,1,2) automático sin parte estacional y crearlo como variable darima_auto para luego poder graficarlo y crear la tabla
darima_auto <- Arima(train_ts, 
                order = c(0, 1, 2))  # Especificamos directamente (p=0, d=1, q=2)  

# Mostrar resumen del modelo ajustado
summary(darima_auto)
## Series: train_ts 
## ARIMA(0,1,2) 
## 
## Coefficients:
##           ma1      ma2
##       -0.4636  -0.2689
## s.e.   0.0807   0.0956
## 
## sigma^2 = 142585:  log likelihood = -1205.18
## AIC=2416.37   AICc=2416.52   BIC=2425.67
## 
## Training set error measures:
##                     ME     RMSE      MAE       MPE     MAPE      MASE
## Training set -13.43009 374.1563 270.3888 -265.9302 276.4697 0.7077997
##                      ACF1
## Training set -0.002894499

Validación de residuales o errores del modelo

# Diagnóstico del modelo (los residuos deben ser ruido blanco)
checkresiduals(darima_auto)  # Verificar si los residuos son aleatorios y no presentan patrones

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(0,1,2)
## Q* = 85.619, df = 22, p-value = 1.886e-09
## 
## Model df: 2.   Total lags used: 24

Residuos en el tiempo: oscilan alrededor de cero sin tendencia clara, con un pico grande en el 2020 (Impacto por pandemia), coherente con lo observado en las otras variables.

ACF: En la gráfica se ve que hay varios “picos” que sobresalen justo cada 12 meses. Esto significa que el modelo todavía no logró aprender el patrón que se repite cada año en las ventas de carros (tiene subidas fuertes en diciembre y bajan en los primeros meses del año). Por eso, un modelo que no tiene en cuenta ese ciclo anual no es suficiente para esta serie, le falta esa información que es bastante relevante para predecir bien.

Histograma: distribución aproximadamente acampanada mensual, centrada en cero, aunque con presencia de valores atípicos hacia ambos extremos.

Conclusión de el modelo ARIMA(0,1,2): logra explicar bien el comportamiento general de las ventas, pero tiene una falla importante, no logra captar el patrón que se repite cada año (mayores ventas en diciembre, menos al inicio del año). Por eso no se usa como el modelo definitivo, y en su lugar se pasa a un modelo SARIMA, que sí tiene en cuenta ese ciclo anual.

Pronóstico modelo ARIMA automático dentro de muestra o en el set de prueba

# Generar pronóstico para el conjunto de prueba
forecast_arima_auto <- forecast(darima_auto, h = length(test_ts))  # Predecir los valores futuros

# Crear dataframe para gráfico interactivo del pronóstico
forecast_data_auto <- data.frame(Tiempo = time(forecast_arima_auto$mean), 
                            Pronostico = as.numeric(forecast_arima_auto$mean),
                            Observado = as.numeric(test_ts))

# Graficar pronóstico junto con los valores observados reales
p4auto <- ggplot(forecast_data_auto, aes(x = Tiempo)) +
  geom_line(aes(y = Pronostico, color = "Pronóstico")) +
  geom_line(aes(y = Observado, color = "Observado")) +
  ggtitle("Figura 14. Pronóstico vs Observado") +
  xlab("Tiempo") + ylab("variable1")

ggplotly(p4auto)  # Convertir el gráfico en interactivo

Interpretación Figura 14. Modelo automatico (0,1,2):

El modelo automático (0,1,2), se mantiene prácticamente plano en los últimos meses (cerca de 1,900 unidades), mientras que los valores observados muestran un aumento marcado en diciembre (hasta 2,573). Esto confirma la limitación identificada en el diagnóstico de residuos: al no capturar el componente estacional, el modelo subestima fuertemente el pico de fin de año, evidenciando la necesidad de usar el SARIMA como modelo final.

Pronóstico automático dentro del set de prueba como tabla

# Cargar librerías necesarias
library(forecast)
library(dplyr)

# Generar pronóstico con el modelo ARIMA identificado
arima_forecast_auto <- forecast(auto_arima_model_no_seasonal, h = length(test_ts))

# Crear un dataframe con los valores observados y pronosticados
forecast_table_auto <- data.frame(
  Tiempo = time(arima_forecast_auto$mean),  # Extraer las fechas del pronóstico
  Observado = as.numeric(test_ts),  # Valores reales
  Pronosticado = as.numeric(arima_forecast_auto$mean)  # Valores pronosticados
)

# Mostrar la tabla
print(forecast_table_auto)
##     Tiempo Observado Pronosticado
## 1 2025.750      2227     2027.524
## 2 2025.833      2165     1907.982
## 3 2025.917      2573     1907.982

Ahora pronosticamos con el modelo automatico fuera del periodo de análisis, es decir enero 2025

Es decir, le sumamos al periodo de prueb auna observación más. Es decir, se estan pronosticando 4 observaciones o trimestres.

# Cargar librerías necesarias
library(forecast)

# Hacer un pronóstico para el siguiente trimestre (1 período adicional)
next_forecast_auto <- forecast(auto_arima_model_no_seasonal, h = length(test_ts) + 1)

# Extraer el pronóstico del próximo trimestre
next_month_forecast_auto <- data.frame(
  Tiempo = time(next_forecast_auto$mean),  # Extraer la fecha del pronóstico
  Pronostico = as.numeric(next_forecast_auto$mean)  # Valor pronosticado
)

# Mostrar el pronóstico completo
print(next_month_forecast_auto)
##     Tiempo Pronostico
## 1 2025.750   2027.524
## 2 2025.833   1907.982
## 3 2025.917   1907.982
## 4 2026.000   1907.982
# Extraer solo el valor del trimestre adicional (último de la tabla)
next_month <- tail(next_month_forecast_auto, 1)
print(paste("Pronóstico para enero 2025:", next_month$Tiempo, "=", next_month$Pronostico))
## [1] "Pronóstico para enero 2025: 2026 = 1907.9818677847"

Modelo SARIMA automático

Este modelo podria ser una solución o mejora al modelo arima tradicional ya que recoge el efecto estacional de las variables, es recomendable por tanto para datos que si tienen un componente estacional fuerte.

El modelo ajustado en este ejemplo es un SARIMA(0,1,2)(0,0,2)[12], lo que significa:

(0,1,2): Parte ARIMA no estacional: 0 términos autorregresivos (AR). 1 diferenciación (d), lo que indica que la serie fue diferenciada una vez para hacerla estacionaria. 1 término de media móvil (MA).

(0,0,2)[12]: Parte estacional con periodicidad 12 (mensual si los datos son mensuales): 1 término autorregresivo estacional (SAR). 0 diferenciaciones estacionales. 0 términos de media móvil estacionales (SMA).

El modelo SARIMA(0,1,2)(0,0,2)[12] sugiere que:

  • La serie tiene una tendencia no estacionaria, corregida con una diferenciación.
  • Existe una influencia significativa del error pasado (MA(1)).
  • Hay un componente estacional autorregresivo fuerte cada 12 períodos.
  • El ajuste es adecuado según los criterios AIC y BIC, pero se podría comparar con otros modelos para mejorar la predicción.

Identificación automática del modelo SARIMA

# Identificación automática modelo SARIMA
auto_arima_model <- auto.arima(train_ts)  # Busca automáticamente los mejores parámetros del modelo ARIMA
print(auto_arima_model)
## Series: train_ts 
## ARIMA(0,1,2)(0,0,2)[12] 
## 
## Coefficients:
##           ma1      ma2    sma1    sma2
##       -0.3820  -0.2243  0.3151  0.1779
## s.e.   0.0807   0.0931  0.0793  0.0758
## 
## sigma^2 = 122809:  log likelihood = -1192.61
## AIC=2395.21   AICc=2395.59   BIC=2410.71

A continuación, se crea el objeto darima para luegO poder graficar los valores reales y observados:

# Cargar el paquete necesario
library(forecast)

# Ajustar el modelo SARIMA(0,1,2)(0,0,2)[12] #Modelo identificado en el paso anterior
darima <- Arima(train_ts, 
                order = c(0, 1, 2),  # (p,d,q) -> (0,1,2)
                seasonal = list(order = c(0, 0, 2),  # (P,D,Q) -> (0,0,2)
                                period = 12))  # Periodicidad estacional de 12 meses

# Mostrar resumen del modelo ajustado
summary(darima)
## Series: train_ts 
## ARIMA(0,1,2)(0,0,2)[12] 
## 
## Coefficients:
##           ma1      ma2    sma1    sma2
##       -0.3820  -0.2243  0.3151  0.1779
## s.e.   0.0807   0.0931  0.0793  0.0758
## 
## sigma^2 = 122809:  log likelihood = -1192.61
## AIC=2395.21   AICc=2395.59   BIC=2410.71
## 
## Training set error measures:
##                      ME     RMSE      MAE      MPE     MAPE      MASE
## Training set -0.5497827 345.0911 250.9625 -243.357 254.0056 0.6569475
##                     ACF1
## Training set -0.00165435

Validación de residuales del modelo automatico SARIMA

# Diagnóstico del modelo (los residuos deben ser ruido blanco)
checkresiduals(darima)  # Verificar si los residuos son aleatorios y no presentan patrones

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(0,1,2)(0,0,2)[12]
## Q* = 22.388, df = 20, p-value = 0.3198
## 
## Model df: 4.   Total lags used: 24

Residuos en el tiempo: Oscilan alrededor de cero sin patrón sistemático, con el impacto identificado en el 2020 por pandemia.

ACF: A diferencia del modelo anterior, aquí casi todas las barras quedan dentro del rango normal, incluyendo las de los 2 primeros años, que antes se salían. Solo una barra en el año 3 queda justo en el límite, pero es un caso aislado que no afecta el resultado general. Esto confirma que el nuevo modelo sí logró aprender el patrón anual de las ventas.

Histograma: distribución acampanada, similar a la del modelo anterior.

Conclusión del modelo SARIMA(0,1,2)(0,0,2)[12]: Este modelo mejora claramente al anterior, los valores que antes se salían del rango normal (en los años 1 y 2) ahora quedan dentro de lo esperado, y la prueba estadística confirma que ya no queda ningún patrón sin explicar. Gracias a esto, el modelo sí logra anticipar bien el aumento de ventas en diciembre, algo que el modelo simple no lograba

Box.test(residuals(darima), lag = 24, type = "Ljung-Box", fitdf = 4)
## 
##  Box-Ljung test
## 
## data:  residuals(darima)
## X-squared = 22.388, df = 20, p-value = 0.3198
# Generar pronóstico para el conjunto de prueba
forecast_arima <- forecast(darima, h = length(test_ts))  # Predecir los valores futuros

# Crear dataframe para gráfico interactivo del pronóstico
forecast_data <- data.frame(Tiempo = time(forecast_arima$mean), 
                            Pronostico = as.numeric(forecast_arima$mean),
                            Observado = as.numeric(test_ts))

# Graficar pronóstico junto con los valores observados reales
p4 <- ggplot(forecast_data, aes(x = Tiempo)) +
  geom_line(aes(y = Pronostico, color = "Pronóstico")) +
  geom_line(aes(y = Observado, color = "Observado")) +
  ggtitle("Figura 15. Pronóstico vs Observado") +
  xlab("Tiempo") + ylab("Unidad Variable 1")

ggplotly(p4)  # Convertir el gráfico en interactivo

Interpretación Figura 15

El pronóstico del SARIMA también muestra una tendencia de aumento hacia diciembre, mejorando frente al ARIMA no estacional, que se mantenia plano. Sin embargo, aún se observa cierta subestimación del salto real de diciembre (observado (2,573 ) vs pronóstico (2,235)), el modelo captura la dirección del repunte estacional, pero no logra anticipar la magnitud completa del pico de fin de año. Debido a lo anterior es importante establecer límite superior del intervalo de confianza, no solo el valor puntual, para la planeación de diciembre.

Pronóstico del modelo automático SARIMA en el set de prueba-Tabla

# Cargar librerías necesarias
library(forecast)
library(dplyr)

# Generar pronóstico con el modelo ARIMA identificado
arima_forecast <- forecast(auto_arima_model, h = length(test_ts))

# Crear un dataframe con los valores observados y pronosticados
forecast_table <- data.frame(
  Tiempo = time(arima_forecast$mean),  # Extraer las fechas del pronóstico
  Observado = as.numeric(test_ts),  # Valores reales
  Pronosticado = as.numeric(arima_forecast$mean)  # Valores pronosticados
)

# Mostrar la tabla
print(forecast_table)
##     Tiempo Observado Pronosticado
## 1 2025.750      2227     2152.680
## 2 2025.833      2165     2135.206
## 3 2025.917      2573     2235.145

Pronóstico del modelo automático SARIMA fuera de muestra (enero - marzo 2026)

Es decir, le sumamos al periodo de prueba una observación más. Es decir, se estan pronosticando 4 observaciones o meses.

variable1_ts <- ts(data_col$VEH_V, start = c(2012, 1), frequency = 12)

# Reajustar EL MISMO modelo (mismo orden ya diagnosticado y validado) con la serie completa
darima_final <- Arima(variable1_ts, 
                order = c(0, 1, 2),
                seasonal = list(order = c(0, 0, 2), period = 12))

summary(darima_final)
## Series: variable1_ts 
## ARIMA(0,1,2)(0,0,2)[12] 
## 
## Coefficients:
##           ma1      ma2    sma1    sma2
##       -0.3776  -0.2177  0.3206  0.1855
## s.e.   0.0798   0.0915  0.0779  0.0750
## 
## sigma^2 = 121138:  log likelihood = -1213.33
## AIC=2436.67   AICc=2437.04   BIC=2452.26
## 
## Training set error measures:
##                    ME     RMSE      MAE       MPE     MAPE      MASE
## Training set 1.914861 342.8309 248.8381 -238.1417 248.8118 0.6489258
##                      ACF1
## Training set -0.003278863
# Pronóstico para enero, febrero y marzo 2026
pronostico_final <- forecast(darima_final, h = 3, level = c(80, 95))
print(pronostico_final)
##          Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## Jan 2026       2204.984 1758.941 2651.027 1522.819 2887.148
## Feb 2026       2250.008 1724.615 2775.401 1446.489 3053.527
## Mar 2026       2250.648 1695.104 2806.191 1401.017 3100.278
library(knitr)
library(kableExtra)

tabla_pronostico <- data.frame(
  Mes = c("Enero 2026", "Febrero 2026", "Marzo 2026"),
  Pronóstico = round(as.numeric(pronostico_final$mean), 0),
  `IC 80% inf` = round(pronostico_final$lower[,1], 0),
  `IC 80% sup` = round(pronostico_final$upper[,1], 0),
  `IC 95% inf` = round(pronostico_final$lower[,2], 0),
  `IC 95% sup` = round(pronostico_final$upper[,2], 0),
  check.names = FALSE
)

kable(tabla_pronostico, 
      caption = "Figura 16. Pronóstico VEH_V: Enero - Marzo 2026",
      align = "lccccc") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE) %>%
  row_spec(0, bold = TRUE, background = "#2C3E50", color = "white")
Figura 16. Pronóstico VEH_V: Enero - Marzo 2026
Mes Pronóstico IC 80% inf IC 80% sup IC 95% inf IC 95% sup
Enero 2026 2205 1759 2651 1523 2887
Febrero 2026 2250 1725 2775 1446 3054
Marzo 2026 2251 1695 2806 1401 3100

Interpretación Figura 16

El modelo proyecta una estabilización de las ventas de vehículos en el Valle para el primer trimestre de año 2026, entre 2205 y 2251 unidades mensuales, con una leve moderación frente al pico de diciembre de 2025. El rango de incertidumbre se amplía progresivamente hacia marzo, reflejo de la volatilidad histórica del mercado, por lo que el pronóstico debe interpretarse como un valor de referencia central y no como una cifra exacta.

library(ggplot2)
library(plotly)

# Recortar solo los últimos 3 años de historia
historico_reciente <- window(variable1_ts, start = c(2023, 1))

df_hist <- data.frame(
  fecha = as.Date(time(historico_reciente)),
  valor = as.numeric(historico_reciente),
  tipo = "Observado"
)

# Último punto observado (diciembre 2025) - será el "puente" de unión
ultimo_punto <- tail(df_hist, 1)

# Datos del pronóstico
df_forecast <- data.frame(
  fecha = as.Date(time(pronostico_final$mean)),
  valor = as.numeric(pronostico_final$mean),
  lo80 = as.numeric(pronostico_final$lower[,1]),
  hi80 = as.numeric(pronostico_final$upper[,1]),
  lo95 = as.numeric(pronostico_final$lower[,2]),
  hi95 = as.numeric(pronostico_final$upper[,2])
)

# Insertar el último punto observado al inicio del pronóstico, para que la línea conecte
df_forecast_conectado <- rbind(
  data.frame(fecha = ultimo_punto$fecha, valor = ultimo_punto$valor,
             lo80 = ultimo_punto$valor, hi80 = ultimo_punto$valor,
             lo95 = ultimo_punto$valor, hi95 = ultimo_punto$valor),
  df_forecast
)

grafico_zoom <- ggplot() +
  # Banda de confianza 95%
  geom_ribbon(data = df_forecast_conectado, aes(x = fecha, ymin = lo95, ymax = hi95),
              fill = "#4A90D9", alpha = 0.15) +
  # Banda de confianza 80%
  geom_ribbon(data = df_forecast_conectado, aes(x = fecha, ymin = lo80, ymax = hi80),
              fill = "#4A90D9", alpha = 0.3) +
  # Línea histórica observada (negro)
  geom_line(data = df_hist, aes(x = fecha, y = valor), color = "#2C3E50", size = 0.8) +
  geom_point(data = df_hist, aes(x = fecha, y = valor), color = "#2C3E50", size = 1) +
  # Línea del pronóstico (rojo), ahora conectada desde el último punto observado
  geom_line(data = df_forecast_conectado, aes(x = fecha, y = valor), 
            color = "#E74C3C", size = 1, linetype = "dashed") +
  geom_point(data = df_forecast, aes(x = fecha, y = valor), 
             color = "#E74C3C", size = 2.5) +
  ggtitle("Figura 17. Pronóstico VEH_V: Enero - Marzo 2026",
          subtitle = "Negro = observado | Rojo punteado = pronóstico | Bandas azules = intervalos de confianza") +
  xlab("Tiempo") + ylab("Ventas de vehículos nuevos - Valle") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", size = 14),
        plot.subtitle = element_text(size = 10, color = "grey40"))

ggplotly(grafico_zoom)

Interpretación Figura 17

El gráfico muestra que, tras el pico de diciembre de 2025 (2573 unidades), el modelo proyecta una caída hacia enero 2026 (2205) seguida de una leve estabilización en febrero y marzo (2250), coherente con el patrón estacional identificado: el primer trimestre del año es generalmentes es más flojo que el cierre del año anterior. En comparación con el histórico reciente (2023-2025), el nivel proyectado para el primer trimestre de 2026 se mantiene dentro del rango de recuperación que el mercado ha mostrado desde 2024, sin señales de una nueva contracción.

Conclusión:

El análisis de las variables VEH_V, MIN e ICC muestra que el mercado automotor del Valle, información relevante para Fanalca como distribuidor de Autos Honda, atraviesa una recuperación real tras dos golpes fuertes, que fueron la pandemia de 2020 y la crisis de tasas de interés y crédito de 2023, que marcó el punto más bajo de toda la serie histórica. Las ventas minoristas fueron mucho más resilientes ante ambos impactos, y la confianza del consumidor solo empezó a recuperarse de forma sostenida hasta 2025.

Las señales integradas son mixtas: VEH_V y MIN se mueven de forma consistente, pero la relación esperada entre ICC y las ventas de vehículos resultó mucho más débil de lo anticipado, sugiriendo que la confianza del consumidor no anticipa bien el comportamiento de este sector en particular.

El modelo SARIMA(0,1,2)(0,0,2)[12] mostró buen desempeño en el período reciente, aunque su precisión se reduce al evaluarse sobre toda la historia, incluyendo el impacto de 2020, una limitación que se espera en cualquier modelo basado en datos con eventos atípicos. El pronóstico para enero-marzo 2026 proyecta una estabilización entre 2205 y 2251 unidades mensuales, con incertidumbre creciente hacia marzo.

En conjunto, el sector muestra señales sólidas de recuperación, aunque persiste cierta fragilidad frente a choques externos y una confianza del consumidor todavía en consolidación.

Recomendaciones estrategicas:

1. Ajustar el pronóstico de ventas: El modelo proyecta 2205 - 2251 unidades mensuales para el mercado del Valle, pero ya vimos que su precisión se debilita justo en escenarios extremos, como el impacto de la pandemia en el 2020. Por lo que se recomienda, dimensionar el pedido de inventario a la importación usando el límite superior del IC 80% (2775 - 2800 unidades de mercado) como escenario de planeación, no el punto central, así se evita quedarse corto si la recuperación continúa más fuerte de lo esperado.

2. Capitalizar la estacionalidad de diciembre con anticipación real: El patrón de pico en diciembre y caída en el primer trimestre es el hallazgo más predecible y accionable de todo el análisis. Por lo que es importante iniciar la campaña comercial y de financiamiento de fin de año en octubre, dado que el modelo históricamente subestima la magnitud del salto de diciembre, es mejor preparar inventario y equipo comercial con antelación.

3. Posicionar el portafolio SUV de Honda frente a la transición hacia híbridos/eléctricos El contexto sectorial muestra un crecimiento fuerte en vehículos híbridos y eléctricos a nivel nacional. Dado que Honda ya tiene presencia en SUV y Fanalca está posicionada en ese segmento, la recomendación concreta es acelerar la oferta de versiones híbridas de los modelos SUV/familiares que ya vende, aprovechando que el atributo de “tecnología y eficiencia” ya es parte del posicionamiento de marca de Honda, es una extensión natural, no un cambio de estrategia.

4. Establecer una revisión trimestral del modelo, no anual Dado que el mercado ha mostrado capacidad de cambios abruptos dos veces en cinco años (2020 y 2023), un modelo ajustado una sola vez al año pierde relevancia rápido. Seria importante reajustar el SARIMA cada trimestre con los datos más recientes, e incorporar formalmente el nuevo trimestre observado antes de generar el siguiente pronóstico.

Adicionalmente es importante monitorear lo siguientes indicadores de forma continua:

  • VEH_V mensual (mercado regional) vs. pronóstico
  • Participación de híbridos/eléctricos en las ventas totales del sector
  • Brecha pronóstico-observado en diciembre de cada año