library(tidyverse)
library(readxl)
library(ggplot2)
library(dplyr)
library(caret)
library(randomForest)
library(VIM)
library(visdat)
library(vip)
library(readxl)
datos <- read_excel("C:/Users/samuv/Downloads/dataset_demanda_energia.xlsx")
Antes de aplicar algoritmos de ML, es crucial limpiar y transformar los datos que correspondan
vis_miss(datos)
valores_faltantes <- colSums(is.na(datos))
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
set.seed(6942)
datos <- kNN(datos, k = 5, imp_var = FALSE)
sum(is.na(datos))
## [1] 0
datos <- datos %>%
distinct()
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
##
##
##
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.
set.seed(6942)
indices <- createDataPartition(datos$demanda_energia, p = 0.8, list = FALSE)
train_data <- datos[indices, ]
test_data <- datos[-indices, ]
modelo_lm <- lm(demanda_energia ~ ., data = train_data)
predicciones_lm <- predict(modelo_lm, test_data)
vip(modelo_lm, bar = FALSE)
valores_reales <- test_data$demanda_energia
valores_predichos <- predicciones_lm
rmse <- sqrt(mean((valores_reales - valores_predichos)^2))
mae <- mean(abs(valores_reales - valores_predichos))
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)
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_rf <- randomForest(demanda_energia ~ ., data = train_data, ntree = 100)
predicciones_rf <- predict(modelo_rf, test_data)
valores_reales <- test_data$demanda_energia # Valores reales del conjunto de prueba
valores_predichos <- predicciones_rf # Valores predichos por el modelo Random Forest
rmse <- sqrt(mean((valores_reales - valores_predichos)^2))
mae <- mean(abs(valores_reales - valores_predichos))
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)
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
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.
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_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
vip(modelo_ad, bar = FALSE)
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
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.
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.