Consumo Energético – Universidad Surcolombiana (USCO) – Especialización en Estadística
Author
Sergio Andres Beltran, Juan Pablo Donato
Published
April 9, 2026
1 Descripción del Problema e Hipótesis
La Sede Central de la Universidad Surcolombiana (USCO) cuenta con cinco cuentas eléctricas activas (Central 1 a Central 5). La normativa eléctrica colombiana (CREG 015 de 2018) establece que la relación entre energía reactiva y energía activa no debe superar 0.48. El incumplimiento de esta norma genera recargos económicos directos en la factura eléctrica.
El análisis se aborda en dos niveles:
Nivel Sede: ¿El consumo total de energía activa de la sede predice si alguna cuenta incumplirá la norma ese mes?
Nivel Cuenta: ¿El consumo de energía activa de una cuenta individual predice si esa cuenta cumplirá o no la norma?
NoteHipótesis del Estudio
Modelo Simple — Nivel Sede:
\(H_0: \beta_1 = 0\) → La energía activa total NO predice el incumplimiento normativo de la sede.
\(H_1: \beta_1 \neq 0\) → La energía activa total SÍ predice el incumplimiento normativo.
Modelo Múltiple — Nivel Sede:
\(H_0: \beta_1 = \beta_2 = 0\) → Ni la energía activa ni el mes del año explican el incumplimiento.
\(H_1\): Al menos un \(\beta_k \neq 0\) → Alguna variable predice el incumplimiento.
Modelos por Cuenta Individual:
\(H_0: \beta_1 = 0\) → El consumo activo de la cuenta NO predice su propio cumplimiento.
\(H_1: \beta_1 \neq 0\) → El consumo activo SÍ predice el cumplimiento de la cuenta.
2 Descripción de Variables
Ver código
# ── Ruta base — ajusta según tu equipo ───────────────────────────────────────RUTA_BASE <-"C:/Users/ESTUDIANTES/Documents/Working Holydays/"# ── Cargar las dos tablas exportadas por el script de unificación ─────────────dt_cuenta <-read.csv(paste0(RUTA_BASE, "Consumo_Central.csv"),header =TRUE, sep =",")dt_sede <-read.csv(paste0(RUTA_BASE, "Resumen_Sede.csv"),header =TRUE, sep =",")# ── Conversiones de tipo necesarias para los modelos ─────────────────────────dt_cuenta$Cuenta <-factor(dt_cuenta$Cuenta)dt_cuenta$Nombre_Cuenta<-factor(dt_cuenta$Nombre_Cuenta)dt_cuenta$Cumple <-factor(dt_cuenta$Cumple, levels =c("Sí", "No"))dt_cuenta$Cumple_bin <-as.integer(dt_cuenta$Cumple_bin)dt_cuenta$Semestre <-factor(dt_cuenta$Semestre, labels =c("Ene–Jun", "Jul–Dic"))dt_cuenta$Trimestre <-factor(dt_cuenta$Trimestre,labels =c("T1 (Ene-Mar)", "T2 (Abr-Jun)","T3 (Jul-Sep)", "T4 (Oct-Dic)"))dt_sede$Sede_Incumple <-as.integer(dt_sede$Sede_Incumple)# ── Tabla resumen de datos cargados ─────────────────────────────────────resumen_datos <-data.frame(Concepto =c("Registros cuenta-período (Tabla 1)","Registros sede-período (Tabla 2)","Cuentas activas","Período cubierto","Períodos con incumplimiento (sede)"),Valor =c(as.character(nrow(dt_cuenta)),as.character(nrow(dt_sede)),as.character(length(unique(dt_cuenta$Cuenta))),paste(min(dt_cuenta$Ano), "–", max(dt_cuenta$Ano)),as.character(sum(dt_sede$Sede_Incumple))))apa_table(resumen_datos,col.names =c("Concepto", "Valor"),caption ="Resumen de los Datos Cargados",align =c("l", "r"))
tabla_vars <-data.frame(Tabla =c("Tabla 2", "Tabla 2", "Tabla 2", "Tabla 2","Tabla 1", "Tabla 1", "Tabla 1", "Tabla 1", "Tabla 1"),Variable =c("Sede_Incumple", "Activa_Total", "Cuentas_Incumplen","Mes / Semestre","Cumple_bin", "Activa", "Cuenta","Semestre", "Pago"),Tipo =c("Binaria (0/1)", "Continua", "Discreta (0–5)","Ordinal / Factor","Binaria (0/1)", "Continua", "Categórica (5 niveles)","Factor (2 niveles)", "Continua"),Rol =c("**Y — Modelo Sede**", "X principal — Modelo Sede","Descriptiva", "Covariable — Modelo Sede","**Y — Modelo por Cuenta**", "X principal — Modelo Cuenta","Covariable — Modelo Unificado","Covariable — Modelo Cuenta", "Descriptiva"),Descripcion =c("1 = al menos una cuenta incumple ese mes; 0 = todas cumplen","Suma de energía activa de las 5 cuentas (kWh)","Número de cuentas con Reactiva/Activa > 0.48 ese mes","Mes del año (1–12) o agrupado en semestres","1 = cuenta cumple norma ese mes; 0 = incumple","Energía activa individual de la cuenta (kWh)","Identificador de cuenta (Central 1 a Central 5)","1er semestre (Ene–Jun) vs 2do semestre (Jul–Dic)","Valor pagado por la cuenta ese período (COP)" ))apa_table(tabla_vars,col.names =c("Tabla", "Variable", "Tipo", "Rol", "Descripción"),caption ="Diccionario de Variables del Estudio",align =c("l", "l", "l", "l", "l"))
Diccionario de Variables del Estudio
Tabla
Variable
Tipo
Rol
Descripción
Tabla 2
Sede_Incumple
Binaria (0/1)
**Y — Modelo Sede**
1 = al menos una cuenta incumple ese mes; 0 = todas cumplen
Tabla 2
Activa_Total
Continua
X principal — Modelo Sede
Suma de energía activa de las 5 cuentas (kWh)
Tabla 2
Cuentas_Incumplen
Discreta (0–5)
Descriptiva
Número de cuentas con Reactiva/Activa > 0.48 ese mes
Tabla 2
Mes / Semestre
Ordinal / Factor
Covariable — Modelo Sede
Mes del año (1–12) o agrupado en semestres
Tabla 1
Cumple_bin
Binaria (0/1)
**Y — Modelo por Cuenta**
1 = cuenta cumple norma ese mes; 0 = incumple
Tabla 1
Activa
Continua
X principal — Modelo Cuenta
Energía activa individual de la cuenta (kWh)
Tabla 1
Cuenta
Categórica (5 niveles)
Covariable — Modelo Unificado
Identificador de cuenta (Central 1 a Central 5)
Tabla 1
Semestre
Factor (2 niveles)
Covariable — Modelo Cuenta
1er semestre (Ene–Jun) vs 2do semestre (Jul–Dic)
Tabla 1
Pago
Continua
Descriptiva
Valor pagado por la cuenta ese período (COP)
WarningVariables excluidas del modelo — Razón metodológica
Relacion y Reactiva no se incluyen como predictoras porque Cumple se define directamente como Relacion ≤ 0.48, donde Relacion = Reactiva / Activa. Incluirlas sería tautológico: el modelo estaría explicando Y con la misma información usada para construir Y, generando coeficientes artificialmente perfectos sin valor predictivo real.
3 Exploración de Datos
3.1 Distribución del Cumplimiento Normativo
Ver código
# ── Período máximo de referencia ──────────────────────────────────────────────periodo_max <-max(dt_cuenta$Tiempo, na.rm =TRUE) # 291# ── Tabla EPV por cuenta con cobertura temporal ──────────────────────────────epv_tabla <- dt_cuenta %>%group_by(Cuenta, Nombre_Cuenta) %>%summarise(Inicio =min(Tiempo, na.rm =TRUE), Períodos =n(),Esperados = periodo_max - Inicio +1,Faltantes = Esperados - Períodos,Cumple =sum(Cumple =="Sí", na.rm =TRUE),No_Cumple =sum(Cumple =="No", na.rm =TRUE),Pct_Cumple =round(Cumple / Períodos *100, 1),EPV_max_vars =floor(No_Cumple /10),.groups ="drop" )# ── Fila resumen sede ─────────────────────────────────────────────────────────epv_sede <- dt_sede %>%summarise(Inicio =min(Tiempo, na.rm =TRUE), Períodos =n(),Esperados = periodo_max - Inicio +1,Faltantes = Esperados - Períodos,Cumple =sum(Sede_Incumple ==0),No_Cumple =sum(Sede_Incumple ==1),Pct_Cumple =round(Cumple / Períodos *100, 1),EPV_max_vars =floor(No_Cumple /10) ) %>%mutate(Cuenta ="SEDE", Nombre_Cuenta ="Sede Central (todas)") %>%select(Cuenta, Nombre_Cuenta, everything())epv_completa <-bind_rows(epv_tabla, epv_sede)apa_table(epv_completa,col.names =c("Cuenta", "Nombre", "Inicio", "Períodos","Esperados", "Faltantes", "Cumple","Incumple", "% Cumple", "Máx. vars (EPV)"),caption ="Distribución del Cumplimiento Normativo, Cobertura Temporal y Capacidad del Modelo (EPV)",align =c("l", "l", "c", "c", "c", "c", "r", "r", "r", "c"),nota =paste0("Inicio: período secuencial en que la cuenta registra su primera medición. ","Esperados: períodos desde el inicio hasta el período ", periodo_max,". Faltantes: períodos sin registro desde el inicio (huecos en la serie)."))
Distribución del Cumplimiento Normativo, Cobertura Temporal y Capacidad del Modelo (EPV)
Cuenta
Nombre
Inicio
Períodos
Esperados
Faltantes
Cumple
Incumple
% Cumple
Máx. vars (EPV)
167382131
Central 1
1
286
291
5
282
0
98.6
0
167383918
Central 4
1
277
291
14
274
0
98.9
0
167385482
Central 2
1
286
291
5
147
0
51.4
0
357154485
Central 5
32
239
260
21
215
0
90.0
0
847747377
Central 3
265
24
27
3
17
0
70.8
0
SEDE
Sede Central (todas)
1
291
291
0
149
142
51.2
14
Nota. Inicio: período secuencial en que la cuenta registra su primera medición. Esperados: períodos desde el inicio hasta el período 291. Faltantes: períodos sin registro desde el inicio (huecos en la serie).
NoteRegla de los 10 Eventos por Variable (EPV)
La regla EPV del módulo establece: \(\text{Máx. variables} = \frac{\text{Total incumplimientos}}{10}\). Para el modelo a nivel sede (142 incumplimientos) el modelo soporta hasta 14 variables. Para los modelos individuales se usará Semestre en lugar de Mes (12 dummies) para respetar el EPV de cada cuenta.
3.2 Gráfico Principal: Pago, Cuentas Pagadas e Incumplimiento en el Tiempo
Ver código
# Escala de transformación para el eje secundario (0–5 → escala del pago)pago_max <-max(dt_sede$Pago_Total_Sede, na.rm =TRUE)escala_k <- pago_max /5# factor para llevar 0–5 a la escala del pagoggplot(dt_sede, aes(x = Tiempo)) +# ── Área: Cuentas pagadas (fondo) ──────────────────────────────────────────geom_area(aes(y = Cuentas_Pagadas * escala_k),fill ="#AED6F1", alpha =0.4) +# ── Barras: Cuentas que incumplen ──────────────────────────────────────────geom_col(aes(y = Cuentas_Incumplen * escala_k),fill ="#E74C3C", alpha =0.6, width =0.8) +# ── Línea: Pago Total Sede ─────────────────────────────────────────────────geom_line(aes(y = Pago_Total_Sede),color ="#2C3E50", linewidth =1.1) +geom_point(aes(y = Pago_Total_Sede,color =factor(Sede_Incumple)),size =1.8, alpha =0.8) +scale_color_manual(values =c("0"="#27AE60", "1"="#E74C3C"),labels =c("0"="Sede cumple", "1"="Sede incumple"),name ="Estado normativo" ) +# ── Eje secundario (derecho): escala 0–5 ──────────────────────────────────scale_y_continuous(name ="Pago Total Sede (COP)",labels =label_comma(big.mark =".", decimal.mark =","),sec.axis =sec_axis(transform =~ . / escala_k,name ="Número de cuentas (máx. 5)",breaks =0:5 ) ) +labs(title ="Pago Total, Cuentas Pagadas y Cuentas en Incumplimiento — Sede Central USCO",subtitle ="Línea: Pago total mensual | Área azul: cuentas pagadas | Barras rojas: cuentas que incumplen",x ="Período (meses)",caption ="Fuente: USCO — Consumo Sede Central 2000–2025" ) +theme_minimal(base_size =12) +theme(plot.title =element_text(face ="bold", color ="#2C3E50", size =13),plot.subtitle =element_text(color ="#555555", size =10),axis.title.y =element_text(color ="#2C3E50"),axis.title.y.right =element_text(color ="#E74C3C"),legend.position ="bottom",panel.grid.minor =element_blank() )
Interpretación: Los períodos donde las barras rojas son más altas (más cuentas incumpliendo) tienden a coincidir visualmente con picos en el valor del pago, lo que sugiere que el incumplimiento normativo tiene un efecto económico observable. Esta relación motiva la construcción del modelo logístico.
3.3 Consumo Activo por Cuenta en el Tiempo
Ver código
ggplot(dt_cuenta, aes(x = Tiempo, y = Activa /1000,color = Nombre_Cuenta, group = Nombre_Cuenta)) +geom_line(alpha =0.8, linewidth =0.9) +geom_point(aes(shape = Cumple), size =1.5, alpha =0.6) +scale_shape_manual(values =c("Sí"=19, "No"=4),name ="Cumple norma") +scale_color_brewer(palette ="Set1", name ="Cuenta") +labs(title ="Energía Activa por Cuenta — Sede Central USCO",subtitle ="Punto ✕ = período de incumplimiento normativo",x ="Período (meses)",y ="Energía Activa (miles de kWh)",caption ="Fuente: USCO — Consumo Sede Central 2000–2025" ) +theme_minimal(base_size =12) +theme(plot.title =element_text(face ="bold", color ="#2C3E50"),legend.position ="bottom",panel.grid.minor =element_blank() )
4 Modelo Logístico Simple — Nivel Sede
Variable Dependiente (\(Y\)):Sede_Incumple (0 = todas cumplen, 1 = al menos una incumple) Variable Predictora (\(X\)):Activa_Total (kWh totales de la sede ese mes)
4.1 La Función Logística
El modelo no estima directamente si la sede incumplirá, sino la probabilidad de que ocurra el incumplimiento, acotada estrictamente entre 0 y 1 mediante la función sigmoide:
metricas_s <-data.frame( Métrica =c("Exactitud global (Accuracy)","Sensibilidad (Recall — detectar incumplimientos)","Especificidad (descartar cumplimientos)"),Valor =paste0(round(c(acc_s, sens_s, esp_s) *100, 2), "%"),Interpretacion =c("Proporción total de clasificaciones correctas","De todos los meses que SÍ hubo incumplimiento, ¿cuántos detectó el modelo?","De todos los meses donde se cumplió la norma, ¿cuántos identificó correctamente?" ))apa_table(metricas_s,col.names =c("Métrica", "Valor", "Interpretación"),caption ="Métricas de Desempeño — Modelo Simple Sede",align =c("l", "r", "l"))
Métricas de Desempeño — Modelo Simple Sede
Métrica
Valor
Interpretación
Exactitud global (Accuracy)
68.04%
Proporción total de clasificaciones correctas
Sensibilidad (Recall — detectar incumplimientos)
56.34%
De todos los meses que SÍ hubo incumplimiento, ¿cuántos detectó el modelo?
Especificidad (descartar cumplimientos)
79.19%
De todos los meses donde se cumplió la norma, ¿cuántos identificó correctamente?
5 Modelo Logístico Múltiple — Nivel Sede
Se incorpora Mes como covariable categórica (factor con 12 niveles) para evaluar si la estacionalidad mensual — calendarío académico, vacaciones, variaciones climáticas — influye en la probabilidad de incumplimiento, controlando por el nivel de consumo activo. A nivel sede (142 incumplimientos), la regla EPV permite hasta 14 variables, por lo que incluir 11 dummies de mes es estadísticamente viable.
\(\hat{\beta}_1\) = 0.00002957 → Por cada kWh adicional de energía activa total, el log-odds de incumplimiento cambia en 0.00002957 unidades, manteniendo constante el mes.
Cada \(\hat{\beta}_k\) (Mes \(k\)) mide la diferencia en log-odds respecto a Enero (categoría de referencia), controlando por consumo activo.
Meses estadísticamente significativos (p < 0.05): Mes 2, Mes 3, Mes 4, Mes 5, Mes 8, Mes 9, Mes 10, Mes 11.
cuentas <-levels(dt_cuenta$Nombre_Cuenta)resultados_ind <-list()for (cta in cuentas) { dt_sub <- dt_cuenta[dt_cuenta$Nombre_Cuenta == cta, ] n_inc <-sum(dt_sub$Cumple_bin ==0, na.rm =TRUE)if (n_inc <1) {cat(sprintf(" %-12s → Sin incumplimientos. Modelo no ajustado.\n", cta))next } modelo_i <-tryCatch(glm(Cumple_bin ~ Activa, data = dt_sub, family ="binomial"),error =function(e) NULL )if (is.null(modelo_i)) {cat(sprintf(" %-12s → Error al ajustar el modelo.\n", cta))next } coef_i <-coef(modelo_i) pval_i <-summary(modelo_i)$coefficients[2, 4] or_i <-exp(coef_i[2]) aic_i <-AIC(modelo_i) resultados_ind[[cta]] <-data.frame(Cuenta = cta,b0 =round(coef_i[1], 4),b1 =round(coef_i[2], 6),OR =round(or_i, 4),p_valor =round(pval_i, 6),AIC =round(aic_i, 2),Signif =ifelse(pval_i <0.05, "✓ Sí", "✗ No"),Efecto =ifelse(or_i >1,"Riesgo (+Activa → menos cumplimiento)","Protector (+Activa → más cumplimiento)") )}tabla_ind <-do.call(rbind, resultados_ind)apa_table(tabla_ind,col.names =c("Cuenta", "β₀", "β₁ (Activa)", "OR","p-valor", "AIC", "Significativo", "Dirección del efecto"),caption ="Resumen de Modelos Logísticos Simples por Cuenta",align =c("l", "r", "r", "r", "r", "r", "c", "l"))
Resumen de Modelos Logísticos Simples por Cuenta
Cuenta
β₀
β₁ (Activa)
OR
p-valor
AIC
Significativo
Dirección del efecto
Central 1
-4.1310
0.000803
1.0008
0.034879
21.43
✓ Sí
Riesgo (+Activa → menos cumplimiento)
Central 2
3.5379
-0.000046
1.0000
0.000000
274.56
✓ Sí
Protector (+Activa → más cumplimiento)
Central 3
-313.4424
0.055895
1.0575
0.996625
4.00
✗ No
Riesgo (+Activa → menos cumplimiento)
Central 4
3.6513
0.000036
1.0000
0.483543
36.64
✗ No
Riesgo (+Activa → menos cumplimiento)
Central 5
1.6161
0.000564
1.0006
0.026553
153.45
✓ Sí
Riesgo (+Activa → menos cumplimiento)
6.3 Modelo Logístico Unificado — Todas las Cuentas
El modelo unificado evalúa si el efecto de la energía activa sobre el cumplimiento es homogéneo entre cuentas, o si hay cuentas estructuralmente más propensas a incumplir.
1. Balance de los datos: El 48.8% de los períodos registran al menos una cuenta en incumplimiento. Este balance casi perfecto (cercano a 50/50) a nivel sede evita el problema de desbalance de clases que advierte el módulo, haciendo al modelo estadísticamente confiable.
2. Modelo Simple — Nivel Sede: La energía activa total es un predictor estadísticamente significativo (p < 0.05) del incumplimiento normativo de la sede. El OR indica que a mayor consumo activo, mayor es la probabilidad de que alguna cuenta incumpla la norma..
3. Selección por AIC — Nivel Sede: El modelo recomendado es M4: ~ Activa_Total + Mes por tener el menor AIC, balanceando ajuste y parsimonia.
4. Modelos Individuales por Cuenta: Los modelos individuales revelan si el efecto de la energía activa es homogéneo entre cuentas o si algunas tienen un comportamiento diferenciado. La tabla de OR comparativa permite identificar cuáles cuentas son estructuralmente más propensas al incumplimiento.
5. Modelo Unificado: El modelo seleccionado por AIC es M2: ~ Activa + Cuenta. Si Cuenta resulta significativa, confirma que existen diferencias estructurales entre cuentas que van más allá del nivel de consumo activo — posiblemente relacionadas con el tipo de carga eléctrica instalada (motores, aires acondicionados, iluminación) en cada edificio.
Análisis desarrollado para la Universidad Surcolombiana (USCO) — Sede CentralHerramienta: R R version 4.5.3 (2026-03-11 ucrt)