La Inteligencia Artificial (IA) ha transformado profundamente múltiples sectores, consolidándose como una herramienta esencial para enfrentar desafíos complejos y mejorar la eficiencia en diversas industrias. En el corazón de la IA están los algoritmos que capacitan a las máquinas para aprender de grandes cantidades de datos y tomar decisiones informadas. Cuando estos algoritmos se entrenan correctamente, pueden clasificar información, hacer predicciones precisas y descubrir patrones en escenarios donde los métodos tradicionales resultan ineficaces. No obstante, la efectividad de los modelos de IA depende en gran medida de la selección del algoritmo adecuado, la plataforma de desarrollo empleada y el tipo de problema que se busca resolver.
En este analisis estadistico descriptivo se estudiara una base de datos que contiene el desempeño de varios algoritmos de inteligencia artificial sobre un problema especifico, que contiene el desempeño, la precisión, tiempo de entrenamiento y otras caracteristicas correspondientes al proceso de cada algoritmo, caracteristicas que se compararan con el objetivo de resolver la pregunta problema planteada.
En una base de datos la cual contiene el desempeño de distintos algoritmos de IA es inevitable comparar los distintos algoritmos con el fin de encontrar los mejores en ciertos aspectos, como por ejemplo trabajando con un tipo de problema especifico, ya que esta información podria facilitar la resolución de dicho problema, con este contexto el EDA se enfoca en resolver una pregunta propuesta por el equipo, sin tener en cuenta el frameWork, ¿cuál es el algoritmo que logra el mayor puntaje F1 con menor tiempo de entrenamiento en los problemas de regresión?
##
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
## Cargando paquete requerido: Rcpp
## ##
## ## Amelia II: Multiple Imputation
## ## (Version 1.8.2, built: 2024-04-10)
## ## Copyright (C) 2005-2024 James Honaker, Gary King and Matthew Blackwell
## ## Refer to http://gking.harvard.edu/amelia/ for more information
## ##
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats 1.0.0 ✔ purrr 1.0.2
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
##
## Adjuntando el paquete: 'gridExtra'
##
##
## The following object is masked from 'package:dplyr':
##
## combine
##
##
##
## Adjuntando el paquete: 'mice'
##
##
## The following object is masked from 'package:stats':
##
## filter
##
##
## The following objects are masked from 'package:base':
##
## cbind, rbind
##
##
## Cargando paquete requerido: Matrix
##
##
## Adjuntando el paquete: 'Matrix'
##
##
## The following objects are masked from 'package:tidyr':
##
## expand, pack, unpack
##
##
## Cargando paquete requerido: stats4
##
## mi (Version 1.1, packaged: 2022-06-05 05:31:15 UTC; ben)
##
## mi Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Trustees of Columbia University
##
## This program comes with ABSOLUTELY NO WARRANTY.
##
## This is free software, and you are welcome to redistribute it
##
## under the General Public License version 2 or later.
##
## Execute RShowDoc('COPYING') for details.
##
##
## Adjuntando el paquete: 'mi'
##
##
## The following objects are masked from 'package:mice':
##
## complete, pool
##
##
## The following object is masked from 'package:tidyr':
##
## complete
Para comenzar el analisis, es necesario identificar las caracteristicas basicas de la base de datos con la que estamos trabajando, empezando por la dimensión de la base de datos:
dim(datosReadr)
## [1] 560 10
head(datosReadr)
## # A tibble: 6 × 10
## Algorithm Framework Problem_Type Dataset_Type Accuracy Precision Recall
## <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl>
## 1 SVM Scikit-lea… Regression Time Series 0.662 0.693 NA
## 2 K-Means Keras Clustering Time Series 0.744 0.490 0.877
## 3 Neural Network Keras Clustering Image 0.885 0.595 0.969
## 4 SVM Keras Clustering Text 0.842 0.842 0.875
## 5 SVM Scikit-lea… Regression Tabular 0.723 0.686 0.301
## 6 K-Means PyTorch Regression Image 0.637 0.626 7.45
## # ℹ 3 more variables: F1_Score <dbl>, Training_Time <dbl>, Date <dttm>
Esta base esta compuesta por 560 filas y 10 columnas, usando la función head() también se puede observar una muestra inicial del contenido, la base de datos se compone de 560 entradas, cada una indicando un modelo diferente, y 10 variables.
Los nombres de las variables son las siguientes:
names(datosReadr)
## [1] "Algorithm" "Framework" "Problem_Type" "Dataset_Type"
## [5] "Accuracy" "Precision" "Recall" "F1_Score"
## [9] "Training_Time" "Date"
El tipo de variable y ejemplos de los datos que estas reciben aparecen a continuacion:
glimpse(datosReadr)
## Rows: 560
## Columns: 10
## $ Algorithm <chr> "SVM", "K-Means", "Neural Network", "SVM", "SVM", "K-Mea…
## $ Framework <chr> "Scikit-learn", "Keras", "Keras", "Keras", "Scikit-learn…
## $ Problem_Type <chr> "Regression", "Clustering", "Clustering", "Clustering", …
## $ Dataset_Type <chr> "Time Series", "Time Series", "Image", "Text", "Tabular"…
## $ Accuracy <dbl> 0.6618051, 0.7443216, 0.8852037, 0.8416477, 0.7229514, 0…
## $ Precision <dbl> 0.6929447, 0.4900292, 0.5948056, 0.8424142, 0.6856109, 0…
## $ Recall <dbl> NA, 0.8766533, 0.9685424, 0.8748388, 0.3010956, 7.454809…
## $ F1_Score <dbl> 0.4426950, 0.4414046, 0.9644707, 0.7041523, 0.6456472, 0…
## $ Training_Time <dbl> 4.9785924, NA, 3.2825938, 4.0416289, 3.6039908, 3.006475…
## $ Date <dttm> 2023-03-08 11:26:21, 2023-03-09 11:26:21, 2023-03-10 11…
Para falicitar el manejo de los datos categoricos, convertimos estos datos en factores:
datosReadr %>% mutate_if(is.character, as.factor);datosReadr %>% glimpse
## # A tibble: 560 × 10
## Algorithm Framework Problem_Type Dataset_Type Accuracy Precision Recall
## <fct> <fct> <fct> <fct> <dbl> <dbl> <dbl>
## 1 SVM Scikit-le… Regression Time Series 0.662 0.693 NA
## 2 K-Means Keras Clustering Time Series 0.744 0.490 0.877
## 3 Neural Network Keras Clustering Image 0.885 0.595 0.969
## 4 SVM Keras Clustering Text 0.842 0.842 0.875
## 5 SVM Scikit-le… Regression Tabular 0.723 0.686 0.301
## 6 K-Means PyTorch Regression Image 0.637 0.626 7.45
## 7 Neural Network PyTorch Regression Text 0.999 0.637 0.336
## 8 Neural Network Scikit-le… Regression Image 0.713 0.676 0.480
## 9 SVM Keras Regression Time Series NA 0.871 0.342
## 10 Random Forest Keras Regression Text 0.582 0.935 NA
## # ℹ 550 more rows
## # ℹ 3 more variables: F1_Score <dbl>, Training_Time <dbl>, Date <dttm>
## Rows: 560
## Columns: 10
## $ Algorithm <chr> "SVM", "K-Means", "Neural Network", "SVM", "SVM", "K-Mea…
## $ Framework <chr> "Scikit-learn", "Keras", "Keras", "Keras", "Scikit-learn…
## $ Problem_Type <chr> "Regression", "Clustering", "Clustering", "Clustering", …
## $ Dataset_Type <chr> "Time Series", "Time Series", "Image", "Text", "Tabular"…
## $ Accuracy <dbl> 0.6618051, 0.7443216, 0.8852037, 0.8416477, 0.7229514, 0…
## $ Precision <dbl> 0.6929447, 0.4900292, 0.5948056, 0.8424142, 0.6856109, 0…
## $ Recall <dbl> NA, 0.8766533, 0.9685424, 0.8748388, 0.3010956, 7.454809…
## $ F1_Score <dbl> 0.4426950, 0.4414046, 0.9644707, 0.7041523, 0.6456472, 0…
## $ Training_Time <dbl> 4.9785924, NA, 3.2825938, 4.0416289, 3.6039908, 3.006475…
## $ Date <dttm> 2023-03-08 11:26:21, 2023-03-09 11:26:21, 2023-03-10 11…
La base de datos utiliza 10 variables, 5 siendo numericas (dbl) y 5 siendo categoricas (chr):
frecuencias <- table(datosReadr$Algorithm)
print(frecuencias)
##
## K-Means Neural Network Random Forest SVM
## 163 135 126 136
tabla_frecuencia <- as.data.frame(frecuencias)
colnames(tabla_frecuencia) <- c("Algorithm", "Frecuencia")
tabla_frecuencia <- tabla_frecuencia %>%
mutate(Frecuencia_Porcentual = Frecuencia / sum(Frecuencia) * 100)
tabla_frecuencia <- tabla_frecuencia %>%
mutate(Frecuencia_Acumulada = cumsum(Frecuencia))
moda <- tabla_frecuencia$Categoria[which.max(tabla_frecuencia$Frecuencia)]
tabla_frecuencia <- tabla_frecuencia %>%
mutate(Moda = moda)
print(tabla_frecuencia)
## Algorithm Frecuencia Frecuencia_Porcentual Frecuencia_Acumulada
## 1 K-Means 163 29.10714 163
## 2 Neural Network 135 24.10714 298
## 3 Random Forest 126 22.50000 424
## 4 SVM 136 24.28571 560
frecuencias <- table(datosReadr$Framework)
print(frecuencias)
##
## Keras PyTorch Scikit-learn TensorFlow
## 124 135 134 167
tabla_frecuencia <- as.data.frame(frecuencias)
colnames(tabla_frecuencia) <- c("Framework", "Frecuencia")
tabla_frecuencia <- tabla_frecuencia %>%
mutate(Frecuencia_Porcentual = Frecuencia / sum(Frecuencia) * 100)
tabla_frecuencia <- tabla_frecuencia %>%
mutate(Frecuencia_Acumulada = cumsum(Frecuencia))
moda <- tabla_frecuencia$Categoria[which.max(tabla_frecuencia$Frecuencia)]
tabla_frecuencia <- tabla_frecuencia %>%
mutate(Moda = moda)
print(tabla_frecuencia)
## Framework Frecuencia Frecuencia_Porcentual Frecuencia_Acumulada
## 1 Keras 124 22.14286 124
## 2 PyTorch 135 24.10714 259
## 3 Scikit-learn 134 23.92857 393
## 4 TensorFlow 167 29.82143 560
frecuencias <- table(datosReadr$Problem_Type)
print(frecuencias)
##
## Classification Clustering Regression
## 175 196 189
tabla_frecuencia <- as.data.frame(frecuencias)
colnames(tabla_frecuencia) <- c("Problem_Type", "Frecuencia")
tabla_frecuencia <- tabla_frecuencia %>%
mutate(Frecuencia_Porcentual = Frecuencia / sum(Frecuencia) * 100)
tabla_frecuencia <- tabla_frecuencia %>%
mutate(Frecuencia_Acumulada = cumsum(Frecuencia))
moda <- tabla_frecuencia$Categoria[which.max(tabla_frecuencia$Frecuencia)]
tabla_frecuencia <- tabla_frecuencia %>%
mutate(Moda = moda)
print(tabla_frecuencia)
## Problem_Type Frecuencia Frecuencia_Porcentual Frecuencia_Acumulada
## 1 Classification 175 31.25 175
## 2 Clustering 196 35.00 371
## 3 Regression 189 33.75 560
frecuencias <- table(datosReadr$Dataset_Type)
print(frecuencias)
##
## Image Tabular Text Time Series
## 157 136 143 124
tabla_frecuencia <- as.data.frame(frecuencias)
colnames(tabla_frecuencia) <- c("Dataset_Type", "Frecuencia")
tabla_frecuencia <- tabla_frecuencia %>%
mutate(Frecuencia_Porcentual = Frecuencia / sum(Frecuencia) * 100)
tabla_frecuencia <- tabla_frecuencia %>%
mutate(Frecuencia_Acumulada = cumsum(Frecuencia))
moda <- tabla_frecuencia$Categoria[which.max(tabla_frecuencia$Frecuencia)]
tabla_frecuencia <- tabla_frecuencia %>%
mutate(Moda = moda)
print(tabla_frecuencia)
## Dataset_Type Frecuencia Frecuencia_Porcentual Frecuencia_Acumulada
## 1 Image 157 28.03571 157
## 2 Tabular 136 24.28571 293
## 3 Text 143 25.53571 436
## 4 Time Series 124 22.14286 560
summary(datosReadr$"Accuracy")
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 0.5038 0.6236 0.7578 0.8779 0.8824 9.7181 39
summary(datosReadr$"Precision")
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 0.4019 0.5632 0.7195 0.8129 0.8596 9.7320 19
summary(datosReadr$"Recall")
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 0.3001 0.4819 0.6493 0.7486 0.8404 9.3662 20
summary(datosReadr$"F1_Score")
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 0.4000 0.5515 0.7086 0.8122 0.8438 9.3740 20
summary(datosReadr$"Training_Time")
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 0.1032 1.2441 2.4347 2.9910 3.8131 46.9856 20
summary(datosReadr$"Date")
## Min. 1st Qu. Median
## "2023-03-08 11:26:21.07" "2023-07-26 05:26:21.07" "2023-12-12 23:26:21.07"
## Mean 3rd Qu. Max.
## "2023-12-12 23:26:21.07" "2024-04-30 17:26:21.07" "2024-09-17 11:26:21.07"
Por ultimo, un resumen general de toda la base de datos
summary(datosReadr)
## Algorithm Framework Problem_Type Dataset_Type
## Length:560 Length:560 Length:560 Length:560
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
##
## Accuracy Precision Recall F1_Score
## Min. :0.5038 Min. :0.4019 Min. :0.3001 Min. :0.4000
## 1st Qu.:0.6236 1st Qu.:0.5632 1st Qu.:0.4819 1st Qu.:0.5515
## Median :0.7578 Median :0.7195 Median :0.6493 Median :0.7086
## Mean :0.8779 Mean :0.8129 Mean :0.7486 Mean :0.8122
## 3rd Qu.:0.8824 3rd Qu.:0.8596 3rd Qu.:0.8404 3rd Qu.:0.8438
## Max. :9.7181 Max. :9.7320 Max. :9.3662 Max. :9.3740
## NA's :39 NA's :19 NA's :20 NA's :20
## Training_Time Date
## Min. : 0.1032 Min. :2023-03-08 11:26:21.07
## 1st Qu.: 1.2441 1st Qu.:2023-07-26 05:26:21.07
## Median : 2.4347 Median :2023-12-12 23:26:21.07
## Mean : 2.9910 Mean :2023-12-12 23:26:21.07
## 3rd Qu.: 3.8131 3rd Qu.:2024-04-30 17:26:21.07
## Max. :46.9856 Max. :2024-09-17 11:26:21.07
## NA's :20
Vistas las variables, es necesario determinar si existen valores NA que puedan complicar la aplicacion de funciones o interpretacion de la base de datos, un rápido diagnostico que nos permite saber los valores NA y donde pueden ser encontrados, puede realizarse a través del ‘Missingness Map’ o Mapa de valores faltantes:
suppressWarnings(missmap(datosReadr))
Se encontraron datos faltantes en las variables numericas “Precision”, “Recall”, “F1_Score”, “Training_Time” y “Accuracy”, la cantidad de valores NA por variable se muestra a continuacion:
na_colum <- colSums(is.na(datosReadr))
print(na_colum)
## Algorithm Framework Problem_Type Dataset_Type Accuracy
## 0 0 0 0 39
## Precision Recall F1_Score Training_Time Date
## 19 20 20 20 0
El tratamiento de los datos faltantes se realizara através imputación de mediana para asi evitar sesgos a la hora de comparar las variables:
datosReadr_imp = datosReadr
tratamiento_atp <- function(x) {
x[is.na(x)] <- median(x, na.rm = TRUE)
return(x)
}
datosReadr_imp$Accuracy <- tratamiento_atp(datosReadr$Accuracy)
datosReadr_imp$Precision <- tratamiento_atp(datosReadr$Precision)
datosReadr_imp$Recall <- tratamiento_atp(datosReadr$Recall)
datosReadr_imp$F1_Score <- tratamiento_atp(datosReadr$F1_Score)
datosReadr_imp$Training_Time <- tratamiento_atp(datosReadr$Training_Time)
Finalmente comprobamos que tras la imputación se mantenga la normalidad de las variables:
ggp1 <- ggplot(data.frame(value=datosReadr$Accuracy), aes(x=value)) +
geom_histogram(fill="orange", color="red", alpha=0.9) +
ggtitle("Original data") +
xlab("Accuracy") + ylab("Frequency") +
theme_ipsum() +
theme(plot.title = element_text(size=15))
ggp2 <- ggplot(data.frame(value=datosReadr_imp$Accuracy), aes(x=value)) +
geom_histogram(fill="green", color="blue", alpha=0.9) +
ggtitle("Imput data") +
xlab("Accuracy") + ylab("Frequency") +
theme_ipsum() +
theme(plot.title = element_text(size=15))
grid.arrange(ggp1, ggp2, ncol = 2)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 39 rows containing non-finite outside the scale range
## (`stat_bin()`).
## Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): font family
## not found in Windows font database
## Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): font family
## not found in Windows font database
## Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): font family
## not found in Windows font database
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
ggp1 <- ggplot(data.frame(value=datosReadr$Precision), aes(x=value)) +
geom_histogram(fill="orange", color="red", alpha=0.9) +
ggtitle("Original data") +
xlab("Precision") + ylab("Frequency") +
theme_ipsum() +
theme(plot.title = element_text(size=15))
ggp2 <- ggplot(data.frame(value=datosReadr_imp$Precision), aes(x=value)) +
geom_histogram(fill="green", color="blue", alpha=0.9) +
ggtitle("Imput data") +
xlab("Precision") + ylab("Frequency") +
theme_ipsum() +
theme(plot.title = element_text(size=15))
grid.arrange(ggp1, ggp2, ncol = 2)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 19 rows containing non-finite outside the scale range
## (`stat_bin()`).
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
ggp1 <- ggplot(data.frame(value=datosReadr$Recall), aes(x=value)) +
geom_histogram(fill="orange", color="red", alpha=0.9) +
ggtitle("Original data") +
xlab("Recall") + ylab("Frequency") +
theme_ipsum() +
theme(plot.title = element_text(size=15))
ggp2 <- ggplot(data.frame(value=datosReadr_imp$Recall), aes(x=value)) +
geom_histogram(fill="green", color="blue", alpha=0.9) +
ggtitle("Imput data") +
xlab("Recall") + ylab("Frequency") +
theme_ipsum() +
theme(plot.title = element_text(size=15))
grid.arrange(ggp1, ggp2, ncol = 2)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_bin()`).
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
ggp1 <- ggplot(data.frame(value=datosReadr$F1_Score), aes(x=value)) +
geom_histogram(fill="orange", color="red", alpha=0.9) +
ggtitle("Original data") +
xlab("F1 Score") + ylab("Frequency") +
theme_ipsum() +
theme(plot.title = element_text(size=15))
ggp2 <- ggplot(data.frame(value=datosReadr_imp$F1_Score), aes(x=value)) +
geom_histogram(fill="green", color="blue", alpha=0.9) +
ggtitle("Imput data") +
xlab("F1 Score") + ylab("Frequency") +
theme_ipsum() +
theme(plot.title = element_text(size=15))
grid.arrange(ggp1, ggp2, ncol = 2)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_bin()`).
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
ggp1 <- ggplot(data.frame(value=datosReadr$Training_Time), aes(x=value)) +
geom_histogram(fill="orange", color="red", alpha=0.9) +
ggtitle("Original data") +
xlab("Training Time") + ylab("Frequency") +
theme_ipsum() +
theme(plot.title = element_text(size=15))
ggp2 <- ggplot(data.frame(value=datosReadr_imp$Training_Time), aes(x=value)) +
geom_histogram(fill="green", color="blue", alpha=0.9) +
ggtitle("Imput data") +
xlab("Training Time") + ylab("Frequency") +
theme_ipsum() +
theme(plot.title = element_text(size=15))
grid.arrange(ggp1, ggp2, ncol = 2)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_bin()`).
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
A través de las gráficas se puede observar que la diferencia no es significativa y se mantiene la distribución, por lo que se puede continuar con el estudio.
Para analizar la posibilidad de normalidad en el conjunto de datos númericos de la base de datos, se hará de dos formas, una analítica y otra gráfica.
Para la primera usaremos el test de Shapiro-Wilk, para el cual existen dos hipótesis:
1- Hipótesis nula (H0): Los datos provienen de una distribución normal.
2- Hipótesis alternativa (H1): Los datos no provienen de una distribución normal.
Al ejecutar el test se consigue un valor p (p-value) para decidir si rechzar o no la hipótesis nula, si este p-value es menor a 0.05, la hipótesis nula se rechaza, si es maor, significa que podría haber normalidad, observemos cual es el caso:
numeric_vars <- datosReadr[sapply(datosReadr, is.numeric)]
normality_tests <- lapply(numeric_vars, shapiro.test)
print(normality_tests)
## $Accuracy
##
## Shapiro-Wilk normality test
##
## data: X[[i]]
## W = 0.22771, p-value < 2.2e-16
##
##
## $Precision
##
## Shapiro-Wilk normality test
##
## data: X[[i]]
## W = 0.25643, p-value < 2.2e-16
##
##
## $Recall
##
## Shapiro-Wilk normality test
##
## data: X[[i]]
## W = 0.31806, p-value < 2.2e-16
##
##
## $F1_Score
##
## Shapiro-Wilk normality test
##
## data: X[[i]]
## W = 0.2547, p-value < 2.2e-16
##
##
## $Training_Time
##
## Shapiro-Wilk normality test
##
## data: X[[i]]
## W = 0.34923, p-value < 2.2e-16
Como se puede ver, todos los p.value son muchos menores a 0.05, pero debemos recordar que este test funciona mejor para muestras pequeñas (de menos de 50 observaciones) y puede ser influenciado por valores extremos, ahora con los gráficso QQ-plot podemos ver que tan cierto es que el test fue influenciado.
Para analizar un gráfico QQ-plot hay que entender sus partes:
1- Eje X (Cuantiles Teóricos): Representa los cuantiles de la distribución teórica con la que estás comparando tus datos (como la distribución normal).
2- Eje Y (Cuantiles Muestrales): Representa los cuantiles de los datos observados.
3- Línea Diagonal: Representa el caso ideal en el que los datos coinciden exactamente con la distribución teórica (por ejemplo, normalidad perfecta). Cuanto más cerca estén los puntos de esta línea, más parecida será la distribución de los datos a la distribución teórica.
como se puede ver, se hace una comparación cuartil-cuartil a eso debe su nombre (en inglés quantile-quantile) el eje X representa la forma que deberían tener los cuartiles si las variables siguen una distribución nomral, y se comparan con los cuartiles reales, los del eje Y.
Si los puntos en la gráfica se acercan mucho a la línea diagonal, se puede decir que es muy probable que la variable siga una distribución normal. Veamos si es el caso:
names_numeric_vars <- names(numeric_vars)
for (var in names_numeric_vars){
qqnorm(datosReadr[[var]], main = paste("QQ Plot -", var))
qqline(datosReadr[[var]], col = "red")
}
Ahora utilizaremos graficas de cajas y bigotes con cada variable para describir su comportamiento e identificar los datos atipicos:
variables <- c("Accuracy", "Precision", "F1_Score", "Training_Time", "Recall")
for (var in variables) {
boxplot(datosReadr[[var]], main = var, ylab = var)
atipicos <- boxplot.stats(datosReadr[[var]])$out
if (length(atipicos) > 0) {
text(x = rep(1, length(atipicos)), y = atipicos, labels = round(atipicos, 2), pos = 4, col = "purple")
}
}
Se puede observar la cantidad de valores atipicos en cada variable, para evitar que estos puedan afectar el estudio de la base de datos se les dará su respectivo tratamiento, se extraeran de la base de datos, se reemplazaran por la media en cada variable y se almacenaran los datos atipicos de cada variable en un dataset aparte para su posterior estudio:
conversion_atp <- function(x) {
iqr <- IQR(x, na.rm = TRUE)
cuartil1 <- quantile(x, 0.25, na.rm = TRUE)
cuartil3 <- quantile(x, 0.75, na.rm = TRUE)
lim_inferior <- cuartil1 - 1.5 * iqr
lim_superior <- cuartil3 + 1.5 * iqr
x <- ifelse(x < lim_inferior | x > lim_superior, NA, x)
return(x)
}
datosReadr$Accuracy <- conversion_atp(datosReadr$Accuracy)
datosReadr$Precision <- conversion_atp(datosReadr$Precision)
datosReadr$Recall <- conversion_atp(datosReadr$Recall)
datosReadr$F1_Score <- conversion_atp(datosReadr$F1_Score)
datosReadr$Training_Time <- conversion_atp(datosReadr$Training_Time)
tratamiento_atp <- function(x) {
x[is.na(x)] <- median(x, na.rm = TRUE)
return(x)
}
datosReadr$Accuracy <- tratamiento_atp(datosReadr$Accuracy)
datosReadr$Precision <- tratamiento_atp(datosReadr$Precision)
datosReadr$Recall <- tratamiento_atp(datosReadr$Recall)
datosReadr$F1_Score <- tratamiento_atp(datosReadr$F1_Score)
datosReadr$Training_Time <- tratamiento_atp(datosReadr$Training_Time)
Hecho el tratamiento, se procede a observar nuevamente cada variable en el boxplot:
variables <- c("Accuracy", "Precision", "F1_Score", "Training_Time", "Recall")
for (var in variables) {
boxplot(datosReadr[[var]], main = var, ylab = var)
atipicos <- boxplot.stats(datosReadr[[var]])$out
if (length(atipicos) > 0) {
text(x = rep(1, length(atipicos)), y = atipicos, labels = round(atipicos, 2), pos = 4, col = "purple")
}
}
Se puede apreciar el cambio en la curva de normalidad después del tratamiento de los valores atipicos:
names_numeric_vars <- names(numeric_vars)
for (var in names_numeric_vars){
qqnorm(datosReadr[[var]], main = paste("QQ Plot -", var))
qqline(datosReadr[[var]], col = "red")
}
Hecho el tratamiento a la base de datos y explicada cada una de las variables, se puede proceder a analizar la pregunta y encontrar solución, se está buscando el algoritmo que tenga mayor puntaje F1 con el menor tiempo de entrenamiento en problemas de regresión.
tabla_uso <- datosReadr %>%
group_by(Algorithm, Problem_Type) %>%
summarise(Count = n(), .groups = "drop")
# Crear el gráfico con etiquetas
ggplot(tabla_uso, aes(x = Algorithm, y = Count, fill = Problem_Type)) +
geom_bar(stat = "identity", position = "dodge") +
geom_text(aes(label = Count),
position = position_dodge(width = 0.9),
vjust = -0.5, # Ajustar la posición vertical de la etiqueta
size = 3) + # Tamaño de la fuente
labs(title = "Uso de Algoritmos por Tipo de Problema",
x = "Algoritmo",
y = "Cantidad de Usos",
fill = "Tipo de Problema") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
En el gráfico anterior se muestra el uso de cada uno de estos algoritmos en cada tipo de problemas, y se puede observar que los dos más usados para problemas de regresión son el SVM y K-Means, además se puede apreciar que cada uno de los algoritmos tiene un enfoque a cierto tipo de problema, para continuar con el estudio de la pregunta, vamos a analizar como es el desempeño de estos algoritmos en problemas de regresión:
datos_regresion <- datosReadr %>%
filter(Algorithm %in% c("SVM", "K-Means") & Problem_Type == "Regression")
promedios <- datos_regresion %>%
group_by(Algorithm) %>%
summarise(promedio_f1 = mean(F1_Score, na.rm = TRUE))
conteo_por_encima <- datos_regresion %>%
left_join(promedios, by = "Algorithm") %>%
mutate(encima_promedio = F1_Score > promedio_f1) %>%
group_by(Algorithm) %>%
summarise(conteo_encima = sum(encima_promedio))
resultados <- promedios %>%
left_join(conteo_por_encima, by = "Algorithm")
ggplot(datos_regresion, aes(x = Algorithm, y = F1_Score, fill = Algorithm)) +
geom_boxplot() + # Boxplot para mostrar la distribución del puntaje F1
geom_jitter(alpha = 0.5, width = 0.2) + # Añadir puntos individuales
geom_text(data = resultados, aes(x = Algorithm, y = max(datos_regresion$F1_Score) + 0.05,
label = paste("Encima del promedio:", conteo_encima)),
color = "black", size = 5, vjust = 0) + # Etiquetas con conteo
labs(title = "Comparación del Puntaje F1 en Problemas de Regresión",
x = "Algoritmo",
y = "Puntaje F1") +
theme_minimal()
# 2. Gráfico para comparar el puntaje F1 con el tiempo de entrenamiento
ggplot(datos_regresion, aes(x = Training_Time, y = F1_Score, color = Algorithm)) +
geom_point(size = 3, alpha = 0.6) + # Puntos
geom_smooth(method = "lm", se = FALSE) + # Línea de tendencia
labs(title = "Puntaje F1 vs. Tiempo de Entrenamiento en Problemas de Regresión",
x = "Tiempo de Entrenamiento",
y = "Puntaje F1") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
En la primera comparativa,se puede observar que a primera vista la diferencia de los puntajes F1 de ambos algoritmos no es tan significativa, el algoritmo k-means presenta un rango intercuartil mayor entre sus puntajes F1 y un promedio mayor, sin embargo el algoritmo SVM tiene más puntajes por encima de su promedio comparado a K-Means.
En la segunda comparativa en la cual se puede apreciar el Tiempo de entrenamiento Contra El puntaje F1, lo primero a evidenciar es que los puntajes se encuentran demasiado dispersos respecto al tiempo, es decir, no existe una correlación entre el tiempo de entrenamiento y el puntaje F1, aparte de eso se puede ver que el algoritmo K-Means obtiene un mejor puntaje con un menor tiempo de entrenamiento comparado con SVM, que unicamente supera el puntaje de K-Means poco antes de las 4 horas de entrenamiento.
Por ultimo también es importante analizar los promedios de cada algoritmo respecto al tiempo y respecto su puntaje F1:
## [1] "El promedio del puntaje F1 de K-Means en problemas de regresión es: 0.711391011081969"
## [1] "El promedio del tiempo de entrenamiento de K-Means en problemas de regresión es: 2.57018451039694"
## [1] "El promedio del puntaje F1 de SVM en problemas de regresión es: 0.695920122821653"
## [1] "El promedio del tiempo de entrenamiento de SVM en problemas de regresión es: 2.33723401069937"
En Conclusión, aunque la diferencia no es Realmente Significativa, K-Means es el algoritmo más efectivo a la hora de trabajar con problemas de Regresión, ya que con menor tiempo de entrenamiento logra un puntaje F1 promedio mayor al de SVM, aunque también cabe resaltar que el tiempo de entrenamiento promedio para SVM en los problemas de regresión es inferior al del algoritmo K-Means.