Cargar las Librerias necesarias

library(tidyverse)
library(readxl)
library(ggplot2)
library(dplyr)
library(caret)
library(randomForest)
library(VIM)
library(visdat)
library(vip)

Cargar la base de datos

library(readxl)
datos <- read_excel("C:/Users/samuv/Downloads/dataset_demanda_energia.xlsx")

Preparación de los datos

Antes de aplicar algoritmos de ML, es crucial limpiar y transformar los datos que correspondan

Verificacion de datos faltantes

vis_miss(datos)

Cálculo del número total de valores faltantes por columna

valores_faltantes <- colSums(is.na(datos))

Imprimir el resultado

print(valores_faltantes)
##             id_cliente           tipo_cliente        zona_geográfica 
##                      0                      0                      0 
##          nivel_ingreso       edad_instalación    potencia_contratada 
##                      0                      0                      0 
##            temperatura       humedad_relativa        precipitaciones 
##                      0                      0                      0 
##             día_semana               hora_día               estación 
##                      0                      0                      0 
##            día_laboral   consumo_medio_diario           consumo_pico 
##                      0                      0                      0 
##   variabilidad_consumo        factor_potencia    uso_paneles_solares 
##                      0                      0                      0 
##      capacidad_batería             horas_pico         carga_nocturna 
##                      0                      0                      0 
##          tarifa_actual          costo_mensual subsidio_gubernamental 
##                      0                      0                      0 
##        aumento_consumo       historico_cortes  eficiencia_energética 
##                      0                      0                      0 
##        demanda_energia          nivel_demanda 
##                      0                     59

Imputar los datos faltantes

set.seed(6942)
datos <- kNN(datos, k = 5, imp_var = FALSE)
sum(is.na(datos))
## [1] 0

Eliminar duplicados si existen

datos <- datos %>% 
  distinct()

1. Analisis exploratorio de los datos

Estadísticas descriptivas

summary(datos)
##    id_cliente    tipo_cliente       zona_geográfica    nivel_ingreso     
##  Min.   :    1   Length:10000       Length:10000       Length:10000      
##  1st Qu.: 2501   Class :character   Class :character   Class :character  
##  Median : 5000   Mode  :character   Mode  :character   Mode  :character  
##  Mean   : 5000                                                           
##  3rd Qu.: 7500                                                           
##  Max.   :10000                                                           
##  edad_instalación potencia_contratada  temperatura     humedad_relativa
##  Min.   : 1.012   Min.   : 3.002      Min.   :-4.993   Min.   :10.02   
##  1st Qu.:13.482   1st Qu.:26.706      1st Qu.: 6.641   1st Qu.:32.85   
##  Median :25.372   Median :51.025      Median :17.788   Median :55.63   
##  Mean   :25.499   Mean   :51.142      Mean   :17.686   Mean   :55.37   
##  3rd Qu.:37.648   3rd Qu.:75.349      3rd Qu.:28.913   3rd Qu.:77.85   
##  Max.   :49.998   Max.   :99.993      Max.   :39.992   Max.   :99.99   
##  precipitaciones      día_semana       hora_día       estación        
##  Min.   :  0.0031   Min.   :1.000   Min.   : 0.00   Length:10000      
##  1st Qu.: 50.1243   1st Qu.:2.000   1st Qu.: 5.00   Class :character  
##  Median :100.0344   Median :4.000   Median :12.00   Mode  :character  
##  Mean   :100.2759   Mean   :3.978   Mean   :11.49                     
##  3rd Qu.:149.3453   3rd Qu.:6.000   3rd Qu.:18.00                     
##  Max.   :199.9630   Max.   :7.000   Max.   :23.00                     
##  día_laboral        consumo_medio_diario  consumo_pico    variabilidad_consumo
##  Length:10000       Min.   :100.1        Min.   : 150.1   Min.   :  5.008     
##  Class :character   1st Qu.:324.1        1st Qu.: 410.9   1st Qu.: 41.412     
##  Mode  :character   Median :546.8        Median : 673.0   Median : 77.569     
##                     Mean   :548.4        Mean   : 676.4   Mean   : 77.412     
##                     3rd Qu.:772.4        3rd Qu.: 941.2   3rd Qu.:113.499     
##                     Max.   :999.9        Max.   :1199.9   Max.   :149.998     
##  factor_potencia  uso_paneles_solares capacidad_batería    horas_pico    
##  Min.   :0.5000   Length:10000        Min.   : 0.00029   Min.   : 1.000  
##  1st Qu.:0.6254   Class :character    1st Qu.:12.34136   1st Qu.: 3.750  
##  Median :0.7501   Mode  :character    Median :25.21151   Median : 7.000  
##  Mean   :0.7490                       Mean   :25.13434   Mean   : 6.526  
##  3rd Qu.:0.8726                       3rd Qu.:37.67569   3rd Qu.:10.000  
##  Max.   :1.0000                       Max.   :49.99935   Max.   :12.000  
##  carga_nocturna  tarifa_actual     costo_mensual    subsidio_gubernamental
##  Min.   :10.01   Min.   :0.05007   Min.   : 20.07   Length:10000          
##  1st Qu.:30.80   1st Qu.:0.11302   1st Qu.:141.04   Class :character      
##  Median :50.58   Median :0.17595   Median :261.02   Mode  :character      
##  Mean   :50.40   Mean   :0.17571   Mean   :261.31                         
##  3rd Qu.:70.56   3rd Qu.:0.23821   3rd Qu.:384.83                         
##  Max.   :90.00   Max.   :0.29998   Max.   :499.98                         
##  aumento_consumo   historico_cortes eficiencia_energética demanda_energia 
##  Min.   :-10.000   Min.   : 0.000   Length:10000          Min.   :-269.1  
##  1st Qu.: -2.550   1st Qu.: 2.000   Class :character      1st Qu.: 366.4  
##  Median :  4.858   Median : 5.000   Mode  :character      Median : 497.8  
##  Mean   :  5.023   Mean   : 5.017                         Mean   : 499.5  
##  3rd Qu.: 12.738   3rd Qu.: 8.000                         3rd Qu.: 634.7  
##  Max.   : 19.999   Max.   :10.000                         Max.   :1269.6  
##  nivel_demanda     
##  Length:10000      
##  Class :character  
##  Mode  :character  
##                    
##                    
## 

Histogramas para variables numéricas

ggplot(datos, aes(x = demanda_energia)) + geom_histogram(binwidth = 50, fill = "blue", color = "black") + ggtitle("Distribucion de la demanda de energia")

ggplot(datos, aes(x = temperatura)) + geom_histogram(binwidth = 5, fill = "red", color = "black") + ggtitle("Distribucion de la Temperatura")

#### Boxplots para variables categóricas

ggplot(datos, aes(x = nivel_demanda, y = consumo_medio_diario)) + geom_boxplot() + ggtitle("Consumo Medio Diario por Nivel de Demanda")

ggplot(datos, aes(x = tipo_cliente, y = consumo_medio_diario)) + geom_boxplot() + ggtitle("Consumo Medio Diario por tipo de cliente")

Se concluye que no hay valores atípicos en las variables de interés, por tanto, no es menester su tratamiento.

Además, visualizamos en el dataframe que no es necesario normalizar o estandarizar características, así como codificar variables categóricas.

2. Modelo de Regresión

Variable objetivo “demanda_energia”

set.seed(6942)
indices <- createDataPartition(datos$demanda_energia, p = 0.8, list = FALSE)
train_data <- datos[indices, ]
test_data <- datos[-indices, ]

Modelo de Regresión Lineal

modelo_lm <- lm(demanda_energia ~ ., data = train_data)
predicciones_lm <- predict(modelo_lm, test_data)

Ver importancia

vip(modelo_lm, bar = FALSE)

Calcular métricas de evaluación para “demanda_energia”

valores_reales <- test_data$demanda_energia
valores_predichos <- predicciones_lm      

RMSE: Root Mean Squared Error

rmse <- sqrt(mean((valores_reales - valores_predichos)^2))

MAE: Mean Absolute Error

mae <- mean(abs(valores_reales - valores_predichos))

R²: Coeficiente de Determinación

ss_total <- sum((valores_reales - mean(valores_reales))^2) # Suma total de cuadrados
ss_residual <- sum((valores_reales - valores_predichos)^2) # Suma de cuadrados residuales
r2 <- 1 - (ss_residual / ss_total)

Imprimir las métricas calculadas

cat("=== Métricas del Modelo de Regresión Lineal ===\n")
## === Métricas del Modelo de Regresión Lineal ===
cat("RMSE:", round(rmse, 4), "\n")
## RMSE: 91.3052
cat("MAE:", round(mae, 4), "\n")
## MAE: 69.3463
cat("R²:", round(r2, 4), "\n")
## R²: 0.7905

Modelo de Random Forest

modelo_rf <- randomForest(demanda_energia ~ ., data = train_data, ntree = 100)
predicciones_rf <- predict(modelo_rf, test_data)

Calcular métricas de evaluación para el modelo Random Forest

valores_reales <- test_data$demanda_energia # Valores reales del conjunto de prueba
valores_predichos <- predicciones_rf        # Valores predichos por el modelo Random Forest

RMSE: Root Mean Squared Error

rmse <- sqrt(mean((valores_reales - valores_predichos)^2))

MAE: Mean Absolute Error

mae <- mean(abs(valores_reales - valores_predichos))

R²: Coeficiente de Determinación

ss_total <- sum((valores_reales - mean(valores_reales))^2) # Suma total de cuadrados
ss_residual <- sum((valores_reales - valores_predichos)^2) # Suma de cuadrados residuales
r2 <- 1 - (ss_residual / ss_total)

Imprimir las métricas calculadas

cat("=== Métricas del Modelo Random Forest ===\n")
## === Métricas del Modelo Random Forest ===
cat("RMSE:", round(rmse, 4), "\n")
## RMSE: 92.4136
cat("MAE:", round(mae, 4), "\n")
## MAE: 70.5759
cat("R²:", round(r2, 4), "\n")
## R²: 0.7854

Ver importancia

vip(modelo_rf, bar = FALSE)

Como la regresión lineal presenta un error cuadrático medio menor, un error absoluto nedio menor y además, tiene mayor capacidad explicativa, es el mejor modelo.

3. Modelo de Clasificación

Variable objetivo “nivel_demanda”

datos$nivel_demanda <- as.factor(datos$nivel_demanda)
set.seed(6942)
indices_clas <- createDataPartition(datos$nivel_demanda, p = 0.8, list = FALSE)
train_data_clas <- datos[indices_clas, ]
test_data_clas <- datos[-indices_clas, ]

Modelo de Árbol de Decisión

modelo_ad <- train(nivel_demanda ~ .,
                   data = train_data_clas,
                   method = "rpart")
predicciones_ad <- predict(modelo_ad, test_data_clas)
cm_ad <- confusionMatrix(predicciones_ad, test_data_clas$nivel_demanda)
precision <- cm_ad$overall['Accuracy']
cat("Precisión del modelo:", precision, "\n")
## Precisión del modelo: 0.9969985

Ver importancia

vip(modelo_ad, bar = FALSE)

Modelo de Random Forest para Clasificación

modelo_rf_clas <- randomForest(nivel_demanda ~ ., data = train_data_clas, ntree = 10)
predicciones_rf_clas <- predict(modelo_rf_clas, test_data_clas)
cm_rf <- confusionMatrix(predicciones_rf_clas, test_data_clas$nivel_demanda)
precision <- cm_rf$overall['Accuracy']
cat("Precisión del modelo:", precision, "\n")
## Precisión del modelo: 0.9964982

Ver importancia

vip(modelo_rf_clas, bar = FALSE)

Se puede concluir que el modelo de Árbol de Decisión es mejor que Random Forest ya que tiene una mayor precisión.

4. Recomendaciones

Recomendamos para mejorar las estimaciones del modelo de regresión lineal evaluar el cumplimiento de los supuestos del teorema de Gauss-Markov para que los estimadores sean los mejores estimadores linealmente insesgados con una varianza mínima. Además, para random forest sugerimos experimentar con diferentes cantidades de árboles para encontrar un equilibrio entre precisión y tiempo de cálculo. Por último, para los árboles de decisión recomendamos limitar la profundidad máxima para prevenir el sobreajuste y que se reduzca la capacidad del modelo para generalizar y funcionar bien en datos nuevos.