Sector

Industria manufacturera — cadena de papel y cartón con foco regional en el Valle del Cauca.

Carvajal S.A.S. es un grupo empresarial de origen caleño con más de 120 años de trayectoria, cuya historia se remonta a 1904, cuando inició sus operaciones como una imprenta en la ciudad de Cali. A lo largo de su trayectoria, la organización ha logrado consolidarse como una empresa de alcance internacional, destacándose por su participación en los sectores de papel, empaques, tecnología y servicios.

La empresa fue seleccionada para el presente análisis debido a que su actividad económica se encuentra directamente relacionada con las tres variables del caso. Asimismo, su trayectoria, capacidad de adaptación e innovación en el sector de papel y empaques la convierten en un caso de interés para analizar el comportamiento de dichas variables a través del tiempo.

Variables

  • IPIR (Índice de Producción Industrial Regional, Valle del Cauca): Esta variable muestra si la industria del Valle del Cauca esta en crecimiento o desaceleración. Como la planta de Carvajal está en esa región, esta variable funciona como un indicador general de cuánta demanda de insumos industriales puede esperar la empresa.

  • X_PAPEL (Exportaciones de papel y cartón, Colombia): Indica qué tanto papel y cartón colombiano se está exportando. Refleja la parte del negocio de Carvajal que depende del mercado internacional, no solo de Colombia.

  • COR_V (Empaques de cartón corrugado, Valle del Cauca): Refleja la producción o demanda de cajas y empaques de cartón en la región. Es la variable más directamente ligada al negocio de Carvajal Empaques, que vende principalmente a clientes industriales como agroindustria y alimentos.

Relación esperada: Se espera que IPIR y COR_V se muevan de manera similar, ya que a mayor actividad industrial en la región, mayor debería ser la demanda de empaques de cartón. X_PAPEL, en cambio, depende más de la demanda externa y de la tasa de cambio, por lo que podría seguir un comportamiento distinto al del mercado interno.

Decisión empresarial que se apoya en este análisis: El resultado de este analisis apoya tanto decisiones operativas como comerciales. En lo operativo, permiten anticipar la capacidad de producción de empaques (turnos e inventario de materia prima) frente a los picos estacionales que comparten IPIR y COR_V. En lo comercial, el cruce de las tres señales ayuda a decidir dónde enfocar esfuerzos: si IPIR y COR_V se desaceleran, priorizar el frente exportador (X_PAPEL), más estable; si la demanda regional de empaques repunta, reforzar la atención al mercado local. Así, la empresa toma decisiones de recursos y prioridad comercial con una base más sólida que una sola variable aislada.

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.

Cargar base de datos

library(readxl)
data_col <- read_excel("~/Maestria Finanzas/Analisis de Datos 2026-2/2.1 Caso 2/Base Caso2 nuevo.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"))

PASO INDISPENSABLE: Declarar las variables como series temporales:

Variable 1

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

Variable 2

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

Variable 3

# Convertir/declarar las exportaciones de combustibles en serie de tiempo mensual
variable3_ts <- ts(data_col$COR_V, 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("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(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 = "Descomposición temporal de la variable 1",
       x = "Tiempo",
       y = "Valor")

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

Tendencia:

La tendencia del IPIR no es lineal, crece de forma moderada hasta 2019, se desploma en 2020, se recupera con fuerza hasta un pico en 2022 y luego se corrige hasta estabilizarse alrededor de 112-113 puntos en 2025, con un crecimiento interanual que cierra el año prácticamente plano (-0.61%).

Estacionalidad:

Hay un patrón estacional claro y repetido cada año, teniendo en cuenta que en los meses de septiembre, octubre y noviembre se presentan los valores más altos, mientras que en enero, febrero y abril los más bajos. Esta información es útil para la empresa porque permite anticipar los picos de actividad industrial regional y planear inventario/capacidad con antelación.

Componente Irregular:

Se observa un choque muy pronunciado alrededor de 2020 (caída cercana a -24 en el residuo) y una segunda caida poco después. La explicación económica corresponde al confinamiento estricto por COVID-19 (abril-junio 2020), que paralizó una gran parte de la producción industrial en Colombia;la segunda caida probablemente refleja el Paro Nacional de 2021, que tuvo epicentro en Cali/Valle del Cauca, con bloqueos de vías que paralizaron los corredores logisticos del pais.

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(time(variable2_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 = "Descomposición temporal de la variable 2",
       x = "Tiempo",
       y = "Valor")

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

Tendencia:

Las exportaciones de papel y cartón tuvieron un comportamiento en forma de “U”: cayeron de manera constante desde 2012 hasta tocar fondo alrededor de 2016-2017, se mantuvieron bajas por varios años (con otro mínimo cerca de 2020-2021), y luego se recuperaron con fuerza entre 2021 y 2024, volviendo casi a los niveles de 2012. Al cierre de 2025 se ve una leve caída, pero la tendencia de fondo sigue siendo positiva: el crecimiento interanual cerró diciembre en +3.19%, algo más moderado que el promedio del último año (+4.87%), lo que indica que las exportaciones siguen creciendo, aunque a menor ritmo.

Estacionalidad:

Se encuentra un factor estacional, sin embargo,las exportaciones dependen más de contratos puntuales y demanda externa que de una época fija del año. Aun así, mayo, julio y octubre suelen ser los meses de mayor exportación, mientras que diciembre, enero y febrero son los más bajos. Esta información sirve principalmente para planear la logística de despachos internacionales, más que para programar la producción.

Componente Irregular:

Esta serie es la más volatil de las tres ya que presenta caídas repentinas recurrentes, sin un choque único tan grande como los de las otras variables. Esto sugiere que su volatilidad viene de factores propios del comercio exterior — variaciones del tipo de cambio, contratos grandes que se despachan en un solo mes, o interrupciones logísticas globales (como la crisis de fletes marítimos de 2021-2022) — más que de un evento puntual identificable.

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(time(variable3_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 = "Descomposición temporal de la variable 3",
       x = "Tiempo",
       y = "Valor")

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

Tendencia:

Los empaques de cartón corrugado en el Valle crecieron poco a poco entre 2012 y 2019. Después vino un golpe fuerte en 2021 (el más severo de las tres variables), seguido de una recuperación muy rápida que llevó la serie a su punto más alto en 2022. Luego bajó de nuevo hasta 2023-2024, y en 2025 volvió a repuntar. Es la variable con más subidas y bajadas bruscas de las tres. El crecimiento interanual lo confirma teniendo en cuenta que cierra diciembre de 2025 en +12.7%, la señal de recuperación más fuerte de las tres variables, aunque también la más volátil.

Estacionalidad:

Hay un patrón que se repite cada año y este coincide exactamente con los meses altos y bajos del IPIR. Septiembre, octubre y noviembre son los meses de mayor producción de empaques, y febrero, diciembre y mayo los más bajos. Esto tiene mucho sentido de negocio: cuando la industria del Valle produce más, también necesita más cajas de cartón para empacar — así que ambas variables suben y bajan juntas en el mismo calendario. Para la empresa, esto es útil porque permite anticipar la demanda de empaques con el mismo calendario que se usa para planear la producción industrial en general.

Componente Irregular:

Es la variable con el choque más extremo de las tres, con una caída cercana a -24 en el residuo, esta se ubicada alrededor de 2021. La explicación económica más probable es el Paro Nacional de 2021, que tuvo epicentro precisamente en Cali/Valle del Cauca, con bloqueos de vías que paralizaron el transporte de materias primas y productos terminados, afectando de forma directa y desproporcionada a esta variable regional.

Integración de señales

cor_niveles <- cor(data.frame(IPIR = as.numeric(variable1_ts), 
                               X_PAPEL = as.numeric(variable2_ts), 
                               COR_V = as.numeric(variable3_ts)))
round(cor_niveles, 3)
##          IPIR X_PAPEL  COR_V
## IPIR    1.000   0.299  0.614
## X_PAPEL 0.299   1.000 -0.093
## COR_V   0.614  -0.093  1.000

IPIR vs. COR_V

Correlación positiva y relevante ≈ 0.61 la cual confirma la hipótesis de que la demanda de empaques de cartón sigue de cerca el ciclo industrial regional. Ambas comparten además el mismo pico estacional (sep-oct-nov).

IPIR vs. X_PAPEL

Correlación positiva pero débil ≈ 0.30, esto se da porque las exportaciones de papel se mueven parcialmente con el comportamiento de la economia nacional, pero conservan una dinámica propia (mercado externo, tasa de cambio).

X_PAPEL vs. COR_V

Correlación prácticamente nula en niveles ≈-0.09, esto confirma que el frente exportador y el frente de empaque regional son en la práctica, dos negocios con lógicas distintas dentro de Carvajal.

Conclusión

las tres señales, en conjunto, son mixtas mayoritariamente positivas hacia el cierre de 2025: la actividad industrial regional (IPIR) se estabiliza tras dos años de corrección, las exportaciones de papel (X_PAPEL) mantienen una tendencia sólida y ascendente teniendo en cuenta que está afectada por factores externos y los empaques de cartón (COR_V) muestran la recuperación más marcada de las tres, aunque también la más volátil.

La serie histórica muestra un sector cíclico pero resiliente; cada caída fuerte (COVID en 2020, Paro Nacional en 2021, tasas altas en 2023-2024) vino de un evento externo puntual, no de un problema estructural del negocio, y siempre fue seguida de recuperación. Hoy el sector está a mitad de camino entre esos extremos ni en crisis ni en pico histórico e IPIR y COR_V mantienen un calendario estacional estable desde hace 14 años, lo que da certeza para planear. En conjunto, esto respalda la lectura de que 2026 arranca en una fase de estabilización post-corrección, con sesgo moderadamente positivo, más que una expansión fuerte o una nueva crisis.

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("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)

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("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)

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("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)

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("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)

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("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)

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("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)

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)

# Gráfico de la tasa de crecimiento anual variable 1
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("Variable1: 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_var1)

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("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)

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
# Gráfico de la tasa de crecimiento anual variable 2
grafico_crecimiento_var3 <- ggplot() +
  geom_line(aes(x = fechas_corregidas_var3, y = tasa_crecimiento_var3), color = "grey", size = 0.7) +
  geom_line(aes(x = fechas_corregidas_var3, y = tasa_tendencia_var3), color = "black", size = 0.8, linetype = "dashed") +
  ggtitle("Variable3: 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_var3)

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.

# 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
#Se crea un nuevo objeto o variable que se llama train_diff, en donde se diferencia la variable 1 , una sola vez:
train_diff <- diff(train_ts, differences = 1) 
library(tseries)
# Prueba de estacionariedad con Augmented Dickey-Fuller (ADF)
adf_test <- adf.test(train_ts) #Se aplica el test ADF a la variable 1 (conjunto de entrenamiento)
print(adf_test) # se muestra el resultado del test
## 
##  Augmented Dickey-Fuller Test
## 
## data:  train_ts
## Dickey-Fuller = -4.598, Lag order = 5, p-value = 0.01
## alternative hypothesis: stationary

El test ADF en la variable 1 arrojó un p-value igual a 0.01, este valor es menor a 0.05, por tanto la serie es estacionaria. De ese modo se debe ejecutar el código siguiente para diferenciar una vez la variable 1 y luego volver a aplicar el test ADF a esa serie diferenciada una vez:

Diferenciación en niveles variable 1

A continuación, se realiza el gráfico de la serie original y diferenciada (una vez) de la variable 1 para ver graficamente el cambio o ajuste:

 # Graficar la serie original en un gráfico separado
  p2 <- ggplot(data.frame(Tiempo = time(train_ts), variable1 = as.numeric(train_ts)), aes(x = Tiempo, y = variable1)) +
    geom_line(color = "blue") +
    ggtitle("Variable 1:Serie Original") +
    xlab("Tiempo") + ylab("Gwh")
  
  ggplotly(p2)  # Convertir en gráfico interactivo
  # Graficar la serie diferenciada en un gráfico separado
  p3 <- ggplot(data.frame(Tiempo = time(train_ts)[-1], variable1_Diff = as.numeric(train_diff)), aes(x = Tiempo, y = variable1_Diff)) +
    geom_line(color = "red") +
    ggtitle("variable 1:Serie Estacionaria (Una diferenciación)") +
    xlab("Tiempo") + ylab("variable 1 diferenciada")
  
  ggplotly(p3)  # Convertir en gráfico interactivo

Modelo ARIMA

library(forecast)
# Graficar ACF y PACF
acf_plot <- ggAcf(train_diff, lag.max = 6) + ggtitle("Autocorrelation Function (ACF)-Determinar q")
pacf_plot <- ggPacf(train_diff, lag.max = 6) + ggtitle("Partial Autocorrelation Function (PACF)-Determinar p")

ggplotly(acf_plot)
ggplotly(pacf_plot)

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. (La división ya se realizó más arriba, antes de la diferenciación y el test ADF, para que train_ts esté disponible en ese punto del documento.)

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(1,1,1) 
## 
## Coefficients:
##          ar1      ma1
##       0.5411  -0.8852
## s.e.  0.1016   0.0582
## 
## sigma^2 = 36.87:  log likelihood = -527.79
## AIC=1061.59   AICc=1061.74   BIC=1070.89
## 
## Training set error measures:
##                     ME    RMSE      MAE       MPE     MAPE      MASE
## Training set 0.6634048 6.01662 4.469225 0.3088081 4.561312 0.8194974
##                     ACF1
## Training set -0.04600409

Modelo ARIMA manual normal (sin tener en cuenta el factor estacional)

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|)    
## ar1  0.541121   0.101620   5.3249  1.01e-07 ***
## ma1 -0.885163   0.058155 -15.2206 < 2.2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Ajuste del modelo ARIMA(4,1,1) manual sin parte estacional y crearlo como variable darima_auto para luego poder graficarlo y crear la tabla
darima_auto <- Arima(train_ts, 
                order = c(4, 1, 1))  # Especificamos directamente (p=4, d=1, q=1)  

# Mostrar resumen del modelo ajustado
summary(darima_auto)
## Series: train_ts 
## ARIMA(4,1,1) 
## 
## Coefficients:
##          ar1     ar2     ar3      ar4      ma1
##       0.4947  0.0585  0.0618  -0.1187  -0.8716
## s.e.  0.1061  0.0905  0.0899   0.0855   0.0775
## 
## sigma^2 = 36.94:  log likelihood = -526.45
## AIC=1064.9   AICc=1065.43   BIC=1083.5
## 
## Training set error measures:
##                     ME     RMSE      MAE       MPE     MAPE      MASE
## Training set 0.6483564 5.966699 4.384499 0.2992403 4.482954 0.8039616
##                     ACF1
## Training set -0.01772698

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(4,1,1)
## Q* = 71.997, df = 19, p-value = 4.27e-08
## 
## Model df: 5.   Total lags used: 24

Modelo ARIMA seleccionado

Pronóstico modelo ARIMA manual 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("Pronóstico vs Observado") +
  xlab("Tiempo") + ylab("variable1")

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

Interpretación modelo manual (4,1,1)

El modelo manual (4,1,1) pronostica mejor dentro de la prueba. Hay un sobre ajuste, pero se capturan muy bien los puntos de quiebre. Es un modelo tentativo adecuado para pronostico fuera de muestra o a futuro.

Interpretación economica del resultado

La gráfica muestra una reducción importante del IPIR observado durante el periodo representado. La serie observada disminuye aproximadamente desde 120,5 hasta 114,6, lo que equivale a una caída cercana al 4,9 %. Este comportamiento indica una pérdida de dinamismo del sector industrial en el corto plazo, posiblemente asociada con una menor demanda, acumulación de inventarios, aumento de los costos de producción o condiciones financieras menos favorables.

El pronóstico del modelo ARIMA(4,1,1) parte de un nivel aproximado de 117,0 y desciende gradualmente hasta 114,9. La trayectoria proyectada también es descendente, por lo que el modelo reconoce la tendencia de debilitamiento industrial; sin embargo, inicialmente subestima la caída observada. Hacia el final del periodo, ambas líneas convergen alrededor de 115, lo cual indica que el modelo logra aproximarse al nivel real, aunque con cierto rezago para capturar la intensidad del ajuste.

Desde el punto de vista económico, la diferencia inicial entre el pronóstico y el valor observado evidencia que se presentó un deterioro más fuerte del esperado. Esto puede interpretarse como la aparición de factores coyunturales o choques recientes que no estaban completamente incorporados en la información histórica utilizada por el modelo. En consecuencia, las predicciones deben actualizarse periódicamente y complementarse con indicadores de ventas, pedidos, costos e inventarios.

La desaceleración del sector industrial puede afectar a Carvajal S. A. mediante varios canales. En primer lugar, una menor actividad industrial puede reducir la demanda empresarial por productos de papel, empaques, soluciones de impresión y otros bienes relacionados con sus líneas de negocio. Si las empresas clientes producen menos, también pueden disminuir sus pedidos y postergar compras o inversiones.

En segundo lugar, el debilitamiento del IPIR puede aumentar la presión competitiva. Ante menores ventas, las empresas suelen competir mediante descuentos, lo que puede reducir los márgenes de Carvajal. Además, si X_PAPEL presenta una evolución similar a la del IPIR, el negocio relacionado con papel podría enfrentar simultáneamente menor demanda y mayores dificultades para trasladar al precio los incrementos en materias primas, energía y transporte.

La señal corregida representada por COR_V permite distinguir si la caída es temporal o estructural. Si COR_V continúa descendiendo, Carvajal debería asumir que existe un debilitamiento más persistente y ajustar su capacidad productiva, compras e inventarios. Si se estabiliza mientras el IPIR observado cae, parte del descenso podría ser transitorio, por lo que convendría evitar recortes permanentes de capacidad y mantener flexibilidad operativa.

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  120.4760     116.0487
## 2 2025.833  115.4923     115.2092
## 3 2025.917  113.6208     114.7549

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

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   116.0487
## 2 2025.833   115.2092
## 3 2025.917   114.7549
## 4 2026.000   114.5091
# 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 2026:", next_month$Tiempo, "=", next_month$Pronostico))
## [1] "Pronóstico para enero 2026: 2026 = 114.509111414238"

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,1)(1,0,0)[12], lo que significa:

(0,1,1): 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).

(1,0,0)[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,1)(1,0,0)[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 dautomá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,1)(1,0,0)[12] 
## 
## Coefficients:
##           ma1    sar1
##       -0.4880  0.4800
## s.e.   0.0797  0.0691
## 
## sigma^2 = 30.18:  log likelihood = -512.79
## AIC=1031.57   AICc=1031.72   BIC=1040.87

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

# Mostrar resumen del modelo ajustado
summary(darima)
## Series: train_ts 
## ARIMA(0,1,1)(1,0,0)[12] 
## 
## Coefficients:
##           ma1    sar1
##       -0.4880  0.4800
## s.e.   0.0797  0.0691
## 
## sigma^2 = 30.18:  log likelihood = -512.79
## AIC=1031.57   AICc=1031.72   BIC=1040.87
## 
## Training set error measures:
##                     ME    RMSE      MAE         MPE     MAPE      MASE
## Training set 0.2350972 5.44314 3.806568 -0.03156947 3.948669 0.6979896
##                    ACF1
## Training set 0.04651848

Validación de residuales del modelo automatico SARIMA

En el correlograma de residuos siguiente se observa que, mejora la correlación de los residuos frente a los dos modelos anteriores. Sin embargo, al comparar los valores reales VS pronosticados se determina una poca coincidencia. Sigue funcionando mejor el modelo automatico (4,1,2)

# 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,1)(1,0,0)[12]
## Q* = 31.787, df = 22, p-value = 0.0811
## 
## Model df: 2.   Total lags used: 24

Pronóstico con el modelo SARIMA dentro del set de prueba-Gráfico líneas

# 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("Pronóstico vs Observado") +
  xlab("Tiempo") + ylab("Unidad Variable 1")

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

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  120.4760     119.6128
## 2 2025.833  115.4923     117.8723
## 3 2025.917  113.6208     117.6773

Pronóstico del modelo automático SARIMA fuera de muestra, es decir, en enero 2026

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

# Cargar librerías necesarias
library(forecast)

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

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

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

Conclusión

El modelo automático ARIMA(4,1,1) fue el que mejor desempeño mostró en la comparación entre los datos reales y los pronosticados dentro del periodo de prueba (oct.nov.dic 2024). Destacó por su mayor precisión en la captura de los puntos de quiebre, lo que lo hace el más confiable.

No obstante, al analizar los residuos de los modelos, se identifican posibles áreas de mejora para robustecer los pronósticos en los tres casos evaluados. Algunas estrategias podrían incluir la aplicación de una transformación logarítmica o trabajar desde el inicio con la serie ajustada por estacionalidad.

Riesgos que enfrenta el sector/empresa

El IPIR regional entra a 2026 con crecimiento interanual casi nulo (-0.61% en diciembre 2025) — si esa desaceleración se profundiza, la demanda de empaques (COR_V), que históricamente sigue de cerca al IPIR (correlación ≈0.61), podría perder el impulso de recuperación que trae desde 2024.

COR_V es la señal más volátil de las tres (mayor peso del componente irregular): la recuperación reciente (+12.7% YoY) puede revertirse con choques puntuales (paros, cambios de pedidos grandes de clientes industriales).

X_PAPEL, aunque sólido, depende de demanda externa y tasa de cambio — factores fuera del control de la empresa y no capturados por el modelo ARIMA/SARIMA univariado.

Oportunidades identificadas

El frente exportador (X_PAPEL) muestra la tendencia más consistente y ascendente de las tres variables, y está relativamente desacoplado del ciclo doméstico — un colchón de ingresos frente a la desaceleración regional.

COR_V viene de su nivel de recuperación interanual más alto en el período analizado, lo que sugiere que la demanda de empaques del Valle está reactivándose más rápido que la actividad industrial general.

La estacionalidad de las tres variables es consistente (pico sep-oct-nov): esto permite planear con anticipación picos de producción y necesidades de capital de trabajo.

Qué debería hacer la empresa / decisiones concretas

  • Producción y capacidad: anticipar el pico estacional de sep-oct-nov (coincide en IPIR y COR_V) reforzando turnos e inventario de materia prima (papel reciclado/kraft) desde julio-agosto, y no esperar la demanda de último momento.

  • Mix comercial: dado que IPIR entra plano a 2026, priorizar en el corto plazo la línea de exportación de papel (X_PAPEL), que mantiene tracción propia, sin descuidar la capacidad para atender el repunte de empaques regionales (COR_V) si se consolida.

  • Gestión de riesgo: no anclar el presupuesto 2026 únicamente al pronóstico puntual del IPIR (111-114); usar el rango del intervalo de confianza (95%: ~99-122) para construir escenarios pesimista/central/optimista de ventas y costos.

Indicadores a monitorear

  • IPIR mensual y crecimiento interanual (YoY): permite identificar de manera temprana cómo está evolucionando la actividad industrial en la región.

  • COR_V mensual: refleja la demanda directa de empaques. Por ello, es importante observar si el crecimiento de 12,7% frente al año anterior se mantiene en los próximos meses o si comienza a disminuir.

  • X_PAPEL y TRM: deben analizarse conjuntamente, ya que las exportaciones de papel pueden verse afectadas tanto por el comportamiento de las ventas en los mercados internacionales como por las variaciones de la tasa de cambio.

Recomendaciones Estrategicas

En el corto plazo, Carvajal S.A.S. debería adoptar una posición prudente, coherente con un IPIR que se proyecta estable pero sin impulso claro para el primer trimestre de 2026: controlar inventarios, priorizar productos y clientes con mayor margen, revisar y renegociar contratos de suministro de materia prima, y monitorear de cerca el comportamiento de los pedidos para anticipar cambios en la demanda. En paralelo, es clave fortalecer la diversificación hacia segmentos menos sensibles al ciclo industrial —como ya lo hace de forma natural el frente exportador de papel, más desacoplado del ciclo doméstico— y avanzar hacia soluciones de mayor valor agregado que permitan sostener márgenes incluso en un entorno de crecimiento moderado.