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(ggplot2)
library(plotly)
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("data_col.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"))
View(data_col)
PASO INDISPENSABLE: Declarar la (s) variable (s) como serie (s) temporal (es):
Variable 1:
# Variable: Producción de concreto premezclado (Metros cúbicos)
concreto_ts <- ts(data_col$CONCRETO, start = c(2012, 1), frequency = 12)
Variable 2:
# Convertir la licc en serie de tiempo mensual
licc_ts <- ts(data_col$LICC, start = c(2012, 1), frequency = 12)
Variable 3:
# Convertir el brent en serie de tiempo mensual
brent_ts <- ts(data_col$BRENT, start = c(2012, 1), frequency = 12)
**Gráfico inicial de la variable 1 en niveles -OrigEn esta sección, se visualiza el comportamiento histórico de la producción de concreto premezclado en metros cúbicos. Como insumo crítico para nuestra empresa, este gráfico nos permite identificar visualmente si la demanda de concreto presenta ciclos estacionales (por ejemplo, bajas en épocas de lluvia o vacaciones de fin de año) y cuál ha sido su evolución tras choques económicos.
# Convertir a gráfico interactivo
# 1. Preparar los datos para ggplot2
# Usamos la variable CONCRETO declarada anteriormente
data_col$variable1 <- as.numeric(concreto_ts)
# 2. Crear el gráfico interactivo de la Serie Original
grafico_concreto <- ggplot(data_col, aes(x = as.Date(FECHA), y = variable1)) +
geom_line(color = "darkred", linewidth = 0.5) +
geom_point(color = "black", size = 0.3, alpha = 0.5) +
labs(
title = "Figura 1. Serie Original: Producción de Concreto Premezclado en Colombia",
subtitle = "Análisis operativo para Estructuras y Prefabricados del Valle S.A. (2012-2026)",
x = "Línea de Tiempo (Mensual)",
y = "Producción (Metros Cúbicos)",
caption = "Fuente: Elaboración propia basada en datos del DANE"
) +
theme_minimal() +
theme(
plot.title = element_text(face = "bold", size = 14),
axis.title = element_text(size = 10)
)
# Convertir a gráfico interactivo
ggplotly(grafico_concreto)
Extracción señales variable 1
# Usamos concreto_ts definido anteriormente
stl_decomp_concreto <- stl(concreto_ts, s.window = "periodic")
# 2. Convertir la descomposición a un data frame (Copiando fielmente tu estructura de clase)
stl_df_concreto <- data.frame(
Time = rep(as.numeric(time(concreto_ts)), 4),
Value = c(stl_decomp_concreto$time.series[, "seasonal"],
stl_decomp_concreto$time.series[, "trend"],
stl_decomp_concreto$time.series[, "remainder"],
as.numeric(concreto_ts)),
Componente = rep(c("Estacionalidad", "Tendencia", "Residuo (Ruido)", "Serie Original"), each = length(concreto_ts))
)
# 3. Crear el gráfico con facetas
grafico_señales_concreto <- ggplot(stl_df_concreto, aes(x = Time, y = Value, color = Componente)) +
geom_line(linewidth = 0.6) +
facet_wrap(~Componente, scales = "free_y", ncol = 1) +
scale_color_manual(values = c("darkorange", "forestgreen", "red", "black")) +
theme_minimal() +
labs(
title = "Figura 2. Extracción de Señales: Producción de Concreto",
subtitle = "Descomposición STL para análisis de Estructuras y Prefabricados del Valle S.A.",
x = "Tiempo (Años)",
y = "Valor / Metros Cúbicos"
) +
theme(legend.position = "none")
# 4. Visualización interactiva
ggplotly(grafico_señales_concreto)
Tendencia (Señal limpia): Muestra el crecimiento o decrecimiento estructural de la demanda de concreto, eliminando las variaciones de mes a mes. Si esta línea sube, la empresa debe considerar ampliar su capacidad instalada.
Estacionalidad: Revela los patrones que se repiten cada año. En la construcción, es común ver caídas en diciembre/enero (vacaciones y festividades) y picos a mitad de año. Esto nos ayuda a programar mantenimientos preventivos de la maquinaria en los meses de baja demanda.
Residuo (Ruido): Representa eventos atípicos (como paros, desastres naturales o choques de oferta). Un residuo muy alto en fechas específicas indica que hubo un factor externo que afectó la producción fuera del ciclo normal.
Extracción de señales: variable 2
# 1. Descomposición de la serie brent_ts (Variable 34 del catálogo)
stl_decomp_brent <- stl(brent_ts, s.window = "periodic")
# 2. Preparar el data frame para visualización (Usando as.numeric para evitar el error previo)
stl_df_brent <- data.frame(
Time = rep(as.numeric(time(brent_ts)), 4),
Value = c(stl_decomp_brent$time.series[, "seasonal"],
stl_decomp_brent$time.series[, "trend"],
stl_decomp_brent$time.series[, "remainder"],
as.numeric(brent_ts)),
Componente = rep(c("Estacionalidad", "Tendencia", "Residuo (Ruido)", "Serie Original"), each = length(brent_ts))
)
# 3. Gráfico con ggplot2
grafico_señales_brent <- ggplot(stl_df_brent, aes(x = Time, y = Value, color = Componente)) +
geom_line(linewidth = 0.6) +
facet_wrap(~Componente, scales = "free_y", ncol = 1) +
scale_color_manual(values = c("darkorange", "forestgreen", "red", "black")) +
theme_minimal() +
labs(
title = "Figura 3. Extracción de Señales: Precio del Petróleo Brent",
subtitle = "Análisis de costos logísticos para Estructuras y Prefabricados del Valle S.A.",
x = "Tiempo (Años)",
y = "Valor (USD/Barril)"
) +
theme(legend.position = "none")
# 4. Interactividad
ggplotly(grafico_señales_brent)
Impacto en Costos: Si la Tendencia (línea verde) del Brent muestra una pendiente positiva, la empresa debe prepararse para un aumento en los costos de distribución. Como ingenieros, esto nos obliga a optimizar las rutas de despacho de concreto para reducir el consumo de combustible.
Ruido (Residuo): El Brent suele tener picos de residuo muy altos debido a conflictos geopolíticos. Estos “sustos” en el precio pueden afectar los márgenes de utilidad de los proyectos de construcción ya contratados.
Decisión Industrial: Al observar la señal limpia (tendencia), podemos decidir si es momento de negociar contratos de suministro a precio fijo con nuestros transportistas o si esperamos una baja en el mercado.
Extracción de señales: Variable 3
# 1. Sincronización de nombres (Usamos licc_ts definida al inicio)
variable2_ts <- licc_ts
# 2. Descomposición de la serie temporal
stl_decomp_var2 <- stl(variable2_ts, s.window = "periodic")
# 3. Estructuración de datos para ggplot2
stl_df_var2 <- data.frame(
Time = rep(as.numeric(time(variable2_ts)), 4),
Value = c(stl_decomp_var2$time.series[, "seasonal"],
stl_decomp_var2$time.series[, "trend"],
stl_decomp_var2$time.series[, "remainder"],
as.numeric(variable2_ts)),
Component = rep(c("Estacional", "Tendencia", "Residuo", "Serie Original"), each = length(variable2_ts))
)
# 4. Construcción del gráfico
p_licc <- ggplot(stl_df_var2, aes(x = Time, y = Value, color = Component)) +
geom_line(linewidth = 0.5) +
facet_wrap(~Component, scales = "free_y", ncol = 1) +
scale_color_manual(values = c("orange", "blue", "red", "black")) +
theme_minimal() +
labs(title = "Figura 4. Descomposición temporal de la Variable 2: Licencias de Construcción (LICC)",
subtitle = "Indicador líder para la planeación de demanda futura",
x = "Tiempo",
y = "Área Aprobada") +
theme(legend.position = "none")
# 5. Renderizado interactivo
ggplotly(p_licc)
Señal de Tendencia (Azul): Esta es la señal más importante para un Ingeniero Industrial. Si la tendencia de las licencias baja, nuestra empresa de prefabricados debe reducir inventarios de cemento y aditivos, pues habrá menos obras en el futuro cercano.
Señal Estacional (Naranja): Revela en qué meses del año las curadurías y planeación urbana aprueban más proyectos. Esto ayuda a Recursos Humanos a planear cuándo contratar más personal de ventas.
Análisis Crítico: Al comparar esta tendencia con la de producción de concreto, podremos ver el “rezago” (lag) entre una licencia aprobada y el primer viaje de concreto a la obra.
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
concreto_sa <- concreto_ts - stl_decomp_concreto$time.series[, "seasonal"]
Se crea la variable2 ajustada por estacionalidad
# Extraer los componentes de la descomposición
licc_sa <- licc_ts - stl_decomp_var2$time.series[, "seasonal"]
Se crea la variable3 ajustada por estacionalidad
# Extraer los componentes de la descomposición
brent_sa <- brent_ts - stl_decomp_brent$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 basado en la longitud de tus datos
fechas <- seq.Date(from = as.Date("2012-01-01"), by = "month", length.out = length(concreto_ts))
# Gráfico Variable 1 (Operativa)
grafico_ajustada_concreto <- ggplot() +
geom_line(aes(x = fechas, y = as.numeric(concreto_ts), color = "Original"), linewidth = 0.5) +
geom_line(aes(x = fechas, y = as.numeric(concreto_sa), color = "Ajustada"), linewidth = 0.7) +
scale_color_manual(values = c("Original" = "grey", "Ajustada" = "blue")) +
labs(title = "Concreto: Serie Original vs Ajustada por Estacionalidad",
subtitle = "Estructuras y Prefabricados del Valle S.A.",
x = "Tiempo", y = "Metros Cúbicos", color = "Leyenda") +
theme_minimal()
ggplotly(grafico_ajustada_concreto)
Gráfico serie original VS ajustada Variable 2
# Gráfico Variable 2 (Indicador Líder)
grafico_ajustada_licc <- ggplot() +
geom_line(aes(x = fechas, y = as.numeric(licc_ts), color = "Original"), linewidth = 0.5) +
geom_line(aes(x = fechas, y = as.numeric(licc_sa), color = "Ajustada"), linewidth = 0.7) +
scale_color_manual(values = c("Original" = "grey", "Ajustada" = "darkgreen")) +
labs(title = "Licencias: Serie Original vs Ajustada por Estacionalidad",
x = "Tiempo", y = "Área Aprobada", color = "Leyenda") +
theme_minimal()
ggplotly(grafico_ajustada_licc)
Gráfico serie original VS ajustada Variable 3
# Gráfico Variable 3 (Costos Logísticos)
grafico_ajustada_brent <- ggplot() +
geom_line(aes(x = fechas, y = as.numeric(brent_ts), color = "Original"), linewidth = 0.5) +
geom_line(aes(x = fechas, y = as.numeric(brent_sa), color = "Ajustada"), linewidth = 0.7) +
scale_color_manual(values = c("Original" = "grey", "Ajustada" = "red")) +
labs(title = "Brent: Serie Original vs Ajustada por Estacionalidad",
x = "Tiempo", y = "USD/Barril", color = "Leyenda") +
theme_minimal()
ggplotly(grafico_ajustada_brent)
Ahora graficamos serie original vs tendencia
Primero se debe obtener la tendencia de cada variable y luego graficarla
Tendencia Variable 1
# 1. Extraer vectores para CONCRETO
# Usamos el objeto stl_decomp_concreto que creamos en los pasos anteriores
concreto_vec <- as.numeric(concreto_ts)
tendencia_concreto <- as.numeric(stl_decomp_concreto$time.series[, "trend"])
# 2. Asegurar que el vector de fechas coincida con la longitud de los datos
fechas <- seq.Date(from = as.Date("2012-01-01"), by = "month", length.out = length(concreto_ts))
# 3. Construcción del Gráfico
grafico_tendencia_concreto <- ggplot() +
geom_line(aes(x = fechas, y = concreto_vec, color = "Serie Original"), linewidth = 0.5) +
geom_line(aes(x = fechas, y = tendencia_concreto, color = "Tendencia"), linewidth = 0.9) +
scale_color_manual(values = c("Serie Original" = "grey", "Tendencia" = "blue")) +
labs(title = "Figura 6. Concreto: Serie Original vs Tendencia",
subtitle = "Análisis de señal limpia para Estructuras y Prefabricados del Valle S.A.",
x = "Tiempo",
y = "Metros Cúbicos",
color = "Leyenda") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
# 4. Renderizado interactivo
ggplotly(grafico_tendencia_concreto)
Tendencia Variable 2
# 1. Extraer vectores para BRENT
# Usamos el objeto stl_decomp_brent que creamos anteriormente
brent_vec <- as.numeric(brent_ts)
tendencia_brent <- as.numeric(stl_decomp_brent$time.series[, "trend"])
# El vector 'fechas' ya fue creado en el paso anterior, por lo que lo reutilizamos
# 2. Construcción del Gráfico
grafico_tendencia_brent <- ggplot() +
geom_line(aes(x = fechas, y = brent_vec, color = "Serie Original"), linewidth = 0.5) +
geom_line(aes(x = fechas, y = tendencia_brent, color = "Tendencia"), linewidth = 0.9) +
scale_color_manual(values = c("Serie Original" = "grey", "Tendencia" = "darkred")) +
labs(title = "Figura 7. Brent: Serie Original vs Tendencia",
subtitle = "Análisis de costos de energía y logística",
x = "Tiempo", y = "USD/Barril", color = "Leyenda") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
# 3. Renderizado interactivo
ggplotly(grafico_tendencia_brent)
Tendencia Variable 3
# 1. Extraer vectores para LICC (Licencias)
licc_vec <- as.numeric(licc_ts)
tendencia_licc <- as.numeric(stl_decomp_var2$time.series[, "trend"])
# 2. Construcción del Gráfico
grafico_tendencia_licc <- ggplot() +
geom_line(aes(x = fechas, y = licc_vec, color = "Serie Original"), linewidth = 0.5) +
geom_line(aes(x = fechas, y = tendencia_licc, color = "Tendencia"), linewidth = 0.9) +
scale_color_manual(values = c("Serie Original" = "grey", "Tendencia" = "orange")) +
labs(title = "Figura 8. Licencias de Construcción: Serie Original vs Tendencia",
subtitle = "Análisis prospectivo de mercado",
x = "Tiempo", y = "Área Aprobada", color = "Leyenda") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
# 3. Renderizado interactivo
ggplotly(grafico_tendencia_licc)
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
# 1. Cálculo de tasa de crecimiento anual para la Serie Original de CONCRETO
# (Dato actual / Dato año anterior - 1) * 100
tasa_crecimiento_concreto <- (concreto_ts[13:length(concreto_ts)] / concreto_ts[1:(length(concreto_ts) - 12)] - 1) * 100
# 2. Cálculo de tasa para la Tendencia (Señal limpia)
# Esto nos dice si el crecimiento es estructural o solo un pico pasajero
tasa_tendencia_concreto <- (tendencia_concreto[13:length(tendencia_concreto)] / tendencia_concreto[1:(length(tendencia_concreto) - 12)] - 1) * 100
# 3. Crear el vector de fechas para el crecimiento (empieza un año después, en 2013)
fechas_crecimiento <- seq(from = as.Date("2013-01-01"), by = "month", length.out = length(tasa_crecimiento_concreto))
# Verificar que las longitudes coincidan para evitar errores en el gráfico
print(paste("Longitud tasa original:", length(tasa_crecimiento_concreto)))
## [1] "Longitud tasa original: 156"
print(paste("Longitud tasa tendencia:", length(tasa_tendencia_concreto)))
## [1] "Longitud tasa tendencia: 156"
*Gráfico variable original y tendencia variable 1: tasa de crecimiento anual**
# Gráfico interactivo Variable 1
grafico_crecimiento_concreto <- ggplot() +
geom_line(aes(x = fechas_crecimiento, y = tasa_crecimiento_concreto, color = "Serie Original"), linewidth = 0.5) +
geom_line(aes(x = fechas_crecimiento, y = tasa_tendencia_concreto, color = "Tendencia"), linewidth = 0.9) +
scale_color_manual(values = c("Serie Original" = "grey", "Tendencia" = "blue")) +
labs(title = "Figura 9. Concreto: Tasa de Crecimiento Anual %",
subtitle = "Original vs Tendencia - Estructuras y Prefabricados del Valle S.A.",
x = "Tiempo", y = "% de Crecimiento", color = "Serie") +
theme_minimal()
ggplotly(grafico_crecimiento_concreto)
Ahora calculamos la tasa de crecimiento de la serie original vs tendencia: variable 2
# 1. Cálculo de tasa de crecimiento anual para el Precio del Brent
# Comparamos el precio de un mes contra el mismo mes del año anterior
tasa_crecimiento_brent <- (brent_ts[13:length(brent_ts)] / brent_ts[1:(length(brent_ts) - 12)] - 1) * 100
# 2. Cálculo de tasa para la Tendencia del Brent
# Esto nos indica la "inflación" estructural de nuestros costos logísticos
tasa_tendencia_brent <- (tendencia_brent[13:length(tendencia_brent)] / tendencia_brent[1:(length(tendencia_brent) - 12)] - 1) * 100
# Verificar longitudes (deben coincidir con las de las variables anteriores)
print(paste("Longitud tasa Brent:", length(tasa_crecimiento_brent)))
## [1] "Longitud tasa Brent: 156"
# 3. Gráfico de Tasas: Original vs Tendencia
grafico_crecimiento_brent <- ggplot() +
geom_line(aes(x = fechas_crecimiento, y = tasa_crecimiento_brent, color = "Serie Original"), linewidth = 0.5) +
geom_line(aes(x = fechas_crecimiento, y = tasa_tendencia_brent, color = "Tendencia"), linewidth = 0.8, linetype = "dashed") +
scale_color_manual(values = c("Serie Original" = "grey", "Tendencia" = "darkred")) +
labs(title = "Figura 10. Brent: Tasa de Crecimiento Anual %",
subtitle = "Análisis de aceleración de costos - Estructuras y Prefabricados del Valle S.A.",
x = "Tiempo", y = "% de Crecimiento", color = "Serie") +
theme_minimal()
ggplotly(grafico_crecimiento_brent)
Ahora calculamos la tasa de crecimiento de la serie original vs tendencia: variable 3
# 1. Cálculo de tasa de crecimiento anual para Licencias (LICC)
tasa_crecimiento_licc <- (licc_ts[13:length(licc_ts)] / licc_ts[1:(length(licc_ts) - 12)] - 1) * 100
# 2. Cálculo de tasa para la Tendencia de Licencias
# Nos permite ver si el sector constructor se está expandiendo o contrayendo estructuralmente
tasa_tendencia_licc <- (tendencia_licc[13:length(tendencia_licc)] / tendencia_licc[1:(length(tendencia_licc) - 12)] - 1) * 100
# Verificar longitudes
print(paste("Longitud tasa Licencias:", length(tasa_crecimiento_licc)))
## [1] "Longitud tasa Licencias: 156"
# 3. Gráfico de Tasas: Original vs Tendencia
grafico_crecimiento_licc <- ggplot() +
geom_line(aes(x = fechas_crecimiento, y = tasa_crecimiento_licc, color = "Serie Original"), linewidth = 0.5) +
geom_line(aes(x = fechas_crecimiento, y = tasa_tendencia_licc, color = "Tendencia"), linewidth = 0.9) +
scale_color_manual(values = c("Serie Original" = "grey", "Tendencia" = "orange")) +
labs(title = "Figura 11. Licencias: Tasa de Crecimiento Anual %",
subtitle = "Aceleración de la demanda futura - Estructuras y Prefabricados del Valle S.A.",
x = "Tiempo", y = "% de Crecimiento", color = "Serie") +
theme_minimal()
ggplotly(grafico_crecimiento_licc)
Señal de Alerta Temprana: Si la tasa de la Tendencia (Naranja) cae por debajo de cero, significa que se están aprobando menos metros cuadrados que el año pasado. Esto es una señal de que la empresa debe ser cautelosa con las inversiones en activos fijos.
Resiliencia: La línea gris tiene caídas fuertes pero la naranja se mantiene estable o positiva, indica que el sector tiene fundamentos sólidos y las caídas son solo ruidos temporales del mercado.