Google define la inteligencia artificial como “un conjunto de tecnologías que permiten que las computadoras realicen una variedad de funciones avanzadas, incluida la capacidad de ver, comprender y traducir lenguaje hablado y escrito, analizar datos, hacer recomendaciones y mucho más” (¿Qué Es la Inteligencia Artificial o IA? | Google Cloud, s. f.). Desde la popularización de herramientas como el chatGPT, Claude, Copilot, entre otras, se ha vuelto muy común que pequeñas, medianas empresas y usuarios avanzados busquen alternativas para crear sus propios algoritmos y sacar el máximo provecho a estas nuevas tecnologías y aplicarlas a sus necesidades específicas. Es aquí como lenguajes más amistosos como Python y sus frameworks entran en juego. Este lenguaje, según Amazon es muy facil de comprender debido a una sintaxis parecida al inglés, es eficiente, pues los scripts tienden a ser más cortos en comparación con otros lenguajes y cuenta con una comunidad de millones de desarrolladores alrededor del mundo, lo que facilita el soporte. Además explican que gracias librerías como Keras, OpenCV-Python, TensorFlow, Scikit-learn, entre otras ponen a Python como la opción más llamativa para científicos de datos realizar tareas de análisis de datos y machine learning (¿Qué Es Python? - Explicación del Lenguaje Python - AWS, s.f.).
Al buscar en internet “frameworks para IA de python” encontramos
infinita información de diversas fuentes. Para usuarios no avanzados
buscando adentrarse en este mundo es normal que surjan dudas como
¿Cuales frameworks existen? ¿Qué puedo construir con ellas? ¿Cómo se
entrenan y cuando tiempo duran en ese proceso?. Entre esas y muchas
preguntas que se pueden responder, para el desarrollo del presente
trabajo se buscará responder:
¿Qué frameworks producen los modelos más precisos en cada tipo
de problema?
install.packages(“readxl”, “tidyr”, “dplyr”, “knitr”, “kableExtra”, “plotly”, “readr”, “ggplot2”, “rworldmap”, “VIM”, “mice”, “naniar”, “Amelia”, “tidyverse”, “hrbrthemes”, “gridExtra”, “missForest”, “outliers”, “lattice”)
# Leer los datos
# archivo <- file.choose()
archivo <- '/Users/pctm/Documents/EDA/Dataset_IA_corte_II.xlsx'
data <- read_excel(archivo, col_names = TRUE)
# Crear la tabla y aplicar estilos
kable(data[1:20,], caption = "Algoritmos de inteligencia artificial utilizando frameworks de python") %>%
kable_styling(full_width = TRUE) %>%
scroll_box(width = "900px", height = "500px")
| Algorithm | Framework | Problem_Type | Dataset_Type | Accuracy | Precision | Recall | F1_Score | Training_Time | Date |
|---|---|---|---|---|---|---|---|---|---|
| SVM | Scikit-learn | Regression | Time Series | 0.6618051 | 0.6929447 | NA | 0.4426950 | 4.9785924 | 2023-03-08 11:26:21 |
| K-Means | Keras | Clustering | Time Series | 0.7443216 | 0.4900292 | 0.8766533 | 0.4414046 | NA | 2023-03-09 11:26:21 |
| Neural Network | Keras | Clustering | Image | 0.8852037 | 0.5948056 | 0.9685424 | 0.9644707 | 3.2825938 | 2023-03-10 11:26:21 |
| SVM | Keras | Clustering | Text | 0.8416477 | 0.8424142 | 0.8748388 | 0.7041523 | 4.0416289 | 2023-03-11 11:26:21 |
| SVM | Scikit-learn | Regression | Tabular | 0.7229514 | 0.6856109 | 0.3010956 | 0.6456472 | 3.6039908 | 2023-03-12 11:26:21 |
| K-Means | PyTorch | Regression | Image | 0.6368133 | 0.6255330 | 7.4548096 | 0.8865271 | 3.0064753 | 2023-03-13 11:26:21 |
| Neural Network | PyTorch | Regression | Text | 0.9985623 | 0.6366858 | 0.3357948 | 0.9014956 | NA | 2023-03-14 11:26:21 |
| Neural Network | Scikit-learn | Regression | Image | 0.7130907 | 0.6756681 | 0.4803251 | 0.5993146 | 2.3283453 | 2023-03-15 11:26:21 |
| SVM | Keras | Regression | Time Series | NA | 0.8710099 | 0.3416673 | 0.8161708 | 3.4064529 | 2023-03-16 11:26:21 |
| Random Forest | Keras | Regression | Text | 0.5818119 | 0.9352508 | NA | 0.8626737 | 3.4199049 | 2023-03-17 11:26:21 |
| SVM | PyTorch | Regression | Image | 0.8974048 | 9.7320081 | 0.7806129 | 0.7927904 | 1.9283008 | 2023-03-18 11:26:21 |
| SVM | Keras | Clustering | Image | 0.8468411 | 0.8721420 | 0.3801413 | 0.4909570 | 4.7142907 | 2023-03-19 11:26:21 |
| SVM | TensorFlow | Clustering | Tabular | 0.6103848 | 0.5892441 | 0.5686872 | 0.9255299 | 0.9200495 | 2023-03-20 11:26:21 |
| SVM | PyTorch | Clustering | Image | 0.5411905 | 0.8128808 | 0.6193656 | 0.7234567 | 2.5517613 | 2023-03-21 11:26:21 |
| K-Means | Keras | Clustering | Text | 0.8402497 | 0.6625619 | 0.5583371 | 0.5694835 | 3.4853315 | 2023-03-22 11:26:21 |
| Neural Network | PyTorch | Regression | Text | NA | 0.5528024 | 0.3847175 | 0.6551369 | 3.5159654 | 2023-03-23 11:26:21 |
| K-Means | TensorFlow | Classification | Tabular | 0.6366298 | 0.9045229 | 0.5932635 | 0.4225427 | 3.2783309 | 2023-03-24 11:26:21 |
| K-Means | PyTorch | Regression | Text | 0.9754318 | 0.4230558 | 0.8258246 | 0.4767201 | 1.4489122 | 2023-03-25 11:26:21 |
| K-Means | PyTorch | Classification | Time Series | 0.5755289 | 0.9410572 | 0.3497054 | 0.8593281 | 0.8654122 | 2023-03-26 11:26:21 |
| SVM | PyTorch | Clustering | Text | 0.7161674 | 0.6768865 | 0.3561260 | 0.4000070 | 3.2161076 | 2023-03-27 11:26:21 |
#Verifico si hay algun problema en la base de datos, sin embargo, todo está funcionando bien
print(problems(data))
## # A tibble: 0 × 4
## # ℹ 4 variables: row <int>, col <int>, expected <chr>, actual <chr>
Esto indica que no se encontraron problemas en los datos, ya que el tibble tiene 0 filas y 4 columnas, es decir el tibble está vacío.
Las variables son:
# Mostrar nombres de las variables
variables <- names(data)
variables
## [1] "Algorithm" "Framework" "Problem_Type" "Dataset_Type"
## [5] "Accuracy" "Precision" "Recall" "F1_Score"
## [9] "Training_Time" "Date"
Verificamos los datos viendo el encabezado y la cola de los datos:
head(data)
## # 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>
tail(data)
## # A tibble: 6 × 10
## Algorithm Framework Problem_Type Dataset_Type Accuracy Precision Recall
## <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl>
## 1 Neural Network Keras Classificati… Image 0.744 0.637 0.443
## 2 K-Means Keras Regression Time Series 0.555 0.653 0.714
## 3 K-Means Keras Regression Tabular 0.774 0.647 0.430
## 4 Random Forest TensorFlow Clustering Image 0.727 NA 0.532
## 5 K-Means TensorFlow Regression Tabular 0.922 0.828 0.899
## 6 Random Forest PyTorch Clustering Image 0.549 0.765 0.445
## # ℹ 3 more variables: F1_Score <dbl>, Training_Time <dbl>, Date <dttm>
dim(data)
## [1] 560 10
Filas: 560 Columnas: 10
Analizamos ahora la estructura de la base de datos:
#Realizo el cambio porque esta variable es numérica.
data$Date <- as.numeric(data$Date)
str(data)
## tibble [560 × 10] (S3: tbl_df/tbl/data.frame)
## $ Algorithm : chr [1:560] "SVM" "K-Means" "Neural Network" "SVM" ...
## $ Framework : chr [1:560] "Scikit-learn" "Keras" "Keras" "Keras" ...
## $ Problem_Type : chr [1:560] "Regression" "Clustering" "Clustering" "Clustering" ...
## $ Dataset_Type : chr [1:560] "Time Series" "Time Series" "Image" "Text" ...
## $ Accuracy : num [1:560] 0.662 0.744 0.885 0.842 0.723 ...
## $ Precision : num [1:560] 0.693 0.49 0.595 0.842 0.686 ...
## $ Recall : num [1:560] NA 0.877 0.969 0.875 0.301 ...
## $ F1_Score : num [1:560] 0.443 0.441 0.964 0.704 0.646 ...
## $ Training_Time: num [1:560] 4.98 NA 3.28 4.04 3.6 ...
## $ Date : num [1:560] 1.68e+09 1.68e+09 1.68e+09 1.68e+09 1.68e+09 ...
library(tibble)
diccionario_variables <- tibble(
Nombre = c(
"Algorithm",
"Framework",
"Problem_Type",
"Dataset_Type",
"Accuracy",
"Precision",
"Recall",
"F1_Score",
"Training_Time",
"Date"
),
Definición = c(
"Tipo de algoritmo de IA utilizado",
"Framework o biblioteca utilizada para la implementación del modelo de IA",
"Tipo de problema abordado por el modelo",
"Tipo de datos utilizados en el entrenamiento del modelo",
"Precisión del modelo en el conjunto de prueba",
"Precisión del modelo en términos de predicciones positivas",
"Sensibilidad del modelo para identificar correctamente los positivos",
"Medida armónica entre precisión y recall",
"Tiempo de entrenamiento del modelo en horas",
"Fecha en la que se realizó la evaluación del modelo"
),
Naturaleza = c(
"Categórica",
"Categórica",
"Categórica",
"Categórica",
"Numérica Continua",
"Numérica Continua",
"Numérica Continua",
"Numérica Continua",
"Numérica Continua",
"Numérica Continua"
),
`Nivel de Medición` = c(
"Nominal",
"Nominal",
"Nominal",
"Nominal",
"Razón",
"Razón",
"Razón",
"Razón",
"Razón",
"Razón"
),
`Criterio de calificación y/o clasificación` = c(
"'Neural Network', 'Random Forest', 'SVM', 'K-Means'",
"'TensorFlow', 'PyTorch', 'Keras', 'Scikit-learn'",
"'Classification', 'Regression', 'Clustering'",
"'Image', 'Text', 'Tabular', 'Time Series'",
"Valor entre [0,1]",
"Valor entre [0,1]",
"Valor entre [0,1]",
"Valor entre [0,1]",
"Tiempo en horas",
"Fecha en formato YYYY-MM-DD"
)
)
# Mostrar la tabla
diccionario_variables
## # A tibble: 10 × 5
## Nombre Definición Naturaleza `Nivel de Medición` Criterio de califica…¹
## <chr> <chr> <chr> <chr> <chr>
## 1 Algorithm Tipo de a… Categórica Nominal 'Neural Network', 'Ra…
## 2 Framework Framework… Categórica Nominal 'TensorFlow', 'PyTorc…
## 3 Problem_Type Tipo de p… Categórica Nominal 'Classification', 'Re…
## 4 Dataset_Type Tipo de d… Categórica Nominal 'Image', 'Text', 'Tab…
## 5 Accuracy Precisión… Numérica … Razón Valor entre [0,1]
## 6 Precision Precisión… Numérica … Razón Valor entre [0,1]
## 7 Recall Sensibili… Numérica … Razón Valor entre [0,1]
## 8 F1_Score Medida ar… Numérica … Razón Valor entre [0,1]
## 9 Training_Ti… Tiempo de… Numérica … Razón Tiempo en horas
## 10 Date Fecha en … Numérica … Razón Fecha en formato YYYY…
## # ℹ abbreviated name: ¹`Criterio de calificación y/o clasificación`
# Crear y estilizar la tabla centrada
tabla_diccionario <- diccionario_variables %>%
kable(caption = "Operacionalización de Variables", align = 'c') %>% # 'align = "c"' centra las columnas
kable_styling(full_width = F, position = "center") %>% # Centra la tabla
column_spec(1, bold = TRUE, color = "darkgrey", border_right = TRUE) %>%
#column_spec(2, background = "lightgrey", border_right = TRUE) %>%
row_spec(0, bold = TRUE, color = "darkblue") # Encabezado en negrita y color rojo
# Mostrar la tabla
tabla_diccionario
| Nombre | Definición | Naturaleza | Nivel de Medición | Criterio de calificación y/o clasificación |
|---|---|---|---|---|
| Algorithm | Tipo de algoritmo de IA utilizado | Categórica | Nominal | ‘Neural Network’, ‘Random Forest’, ‘SVM’, ‘K-Means’ |
| Framework | Framework o biblioteca utilizada para la implementación del modelo de IA | Categórica | Nominal | ‘TensorFlow’, ‘PyTorch’, ‘Keras’, ‘Scikit-learn’ |
| Problem_Type | Tipo de problema abordado por el modelo | Categórica | Nominal | ‘Classification’, ‘Regression’, ‘Clustering’ |
| Dataset_Type | Tipo de datos utilizados en el entrenamiento del modelo | Categórica | Nominal | ‘Image’, ‘Text’, ‘Tabular’, ‘Time Series’ |
| Accuracy | Precisión del modelo en el conjunto de prueba | Numérica Continua | Razón | Valor entre [0,1] |
| Precision | Precisión del modelo en términos de predicciones positivas | Numérica Continua | Razón | Valor entre [0,1] |
| Recall | Sensibilidad del modelo para identificar correctamente los positivos | Numérica Continua | Razón | Valor entre [0,1] |
| F1_Score | Medida armónica entre precisión y recall | Numérica Continua | Razón | Valor entre [0,1] |
| Training_Time | Tiempo de entrenamiento del modelo en horas | Numérica Continua | Razón | Tiempo en horas |
| Date | Fecha en la que se realizó la evaluación del modelo | Numérica Continua | Razón | Fecha en formato YYYY-MM-DD |
En la lectura inicial que se realizó de la base de datos se concluyó que no tenemos problema con ningún dato en particular por tanto no será necesario hacer una conversión. Para facilitar la lectura se traerá a esta sección una tabla con los tipos de datos de cada una de las variables. Para resumir, tenemos 4 variables de tipo chr, 5 num y una de tipo date.
str(data)
## tibble [560 × 10] (S3: tbl_df/tbl/data.frame)
## $ Algorithm : chr [1:560] "SVM" "K-Means" "Neural Network" "SVM" ...
## $ Framework : chr [1:560] "Scikit-learn" "Keras" "Keras" "Keras" ...
## $ Problem_Type : chr [1:560] "Regression" "Clustering" "Clustering" "Clustering" ...
## $ Dataset_Type : chr [1:560] "Time Series" "Time Series" "Image" "Text" ...
## $ Accuracy : num [1:560] 0.662 0.744 0.885 0.842 0.723 ...
## $ Precision : num [1:560] 0.693 0.49 0.595 0.842 0.686 ...
## $ Recall : num [1:560] NA 0.877 0.969 0.875 0.301 ...
## $ F1_Score : num [1:560] 0.443 0.441 0.964 0.704 0.646 ...
## $ Training_Time: num [1:560] 4.98 NA 3.28 4.04 3.6 ...
## $ Date : num [1:560] 1.68e+09 1.68e+09 1.68e+09 1.68e+09 1.68e+09 ...
aggr(data, numbers = TRUE, col = c("navyblue", "red"),
cex.axis = 0.7, gap = 3, ylab = c("Proportion of missingness", "Missingness pattern"))
md.pattern(data, plot = TRUE, rotate.names = TRUE)
## Algorithm Framework Problem_Type Dataset_Type Date Precision Recall
## 448 1 1 1 1 1 1 1
## 39 1 1 1 1 1 1 1
## 16 1 1 1 1 1 1 1
## 17 1 1 1 1 1 1 1
## 2 1 1 1 1 1 1 1
## 18 1 1 1 1 1 1 0
## 1 1 1 1 1 1 1 0
## 16 1 1 1 1 1 0 1
## 1 1 1 1 1 1 0 1
## 1 1 1 1 1 1 0 1
## 1 1 1 1 1 1 0 0
## 0 0 0 0 0 19 20
## F1_Score Training_Time Accuracy
## 448 1 1 1 0
## 39 1 1 0 1
## 16 1 0 1 1
## 17 0 1 1 1
## 2 0 0 1 2
## 18 1 1 1 1
## 1 1 0 1 2
## 16 1 1 1 1
## 1 1 0 1 2
## 1 0 1 1 2
## 1 1 1 1 2
## 20 20 39 118
gg_miss_var(data, show_pct = TRUE)
missmap(data, col = c("yellow", "darkblue"), legend = TRUE)
## Warning: Unknown or uninitialised column: `arguments`.
## Unknown or uninitialised column: `arguments`.
## Warning: Unknown or uninitialised column: `imputations`.
Los gráficos anteriores permiten observar los porcentajes de datos faltantes. Para este dataset el missingness map muestra que se tiene un 98% de datos completos. Los demás representan de distintas formas que se presentan valores faltantes en las variables Precision, F1_Score, Recall, Training_TIme y Accuracy, siendo esta última la que mayor porcentaje tiene (6%).
summary(data)
## 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. :1.678e+09
## 1st Qu.: 1.2441 1st Qu.:1.690e+09
## Median : 2.4347 Median :1.702e+09
## Mean : 2.9910 Mean :1.702e+09
## 3rd Qu.: 3.8131 3rd Qu.:1.714e+09
## Max. :46.9856 Max. :1.727e+09
## NA's :20
Un primer análisis de este dataset incluye un conjunto de 560 observaciones y 10 variables catégoricas y numéricas. Si nos detenemos a observar las variables numéricas tenemos casos como “Accuracy” varía desde un mínimo de 0.5038 hasta un máximo de 9.7181, indicando una amplia gama de resultados en los modelos. Precision que varía entre 0.4019 y 9.7320. Por otro lado, Recall y F1_Score fluctuan entre 0.3 y 9.3 y 0.4 y 9.3, respectivamente. Los tiempos de entrenamiento se extienden desde 0.10 horas hasta 46.9. Las medias de nuestras variables corresponderían a 0.8779, 0.8129, 0.7486, 0.8122 y 2.9910, en el orden mencionado anteriormente.
data_omit <- na.omit(data)
suppressWarnings({
library(ggplot2)
library(tidyverse)
library(hrbrthemes)
library(gridExtra)
library(missForest)
})
ggp1 <- ggplot(data.frame(value=data$Accuracy), aes(x=value)) +
geom_histogram(fill="#FD0000", color="#E52521", alpha=0.9) +
ggtitle("Original data") +
xlab("Accuracy") + ylab("Frequency") +
theme_ipsum() +
theme(plot.title = element_text(size=15))
ggp2 <- ggplot(data.frame(value=data_omit$Accuracy), aes(x=value)) +
geom_histogram(fill="#43B047", color="#049DCB", alpha=0.9) +
ggtitle("Reemplazado por Mediana") +
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()`).
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Se ve en la imagen anterior que omitiendo los datos NA tenemos una distribución con algunas diferencias para datos superiores al 7.5. Debido a eso, imputaremos los datos NA por su mediana.
data_imputados <- data %>%
mutate(
Accuracy = ifelse(is.na(Accuracy), median(Accuracy, na.rm = TRUE), Accuracy),
Precision = ifelse(is.na(Precision), median(Precision, na.rm = TRUE), Precision),
Recall = ifelse(is.na(Recall), median(Recall, na.rm = TRUE), Recall),
F1_Score = ifelse(is.na(F1_Score), median(F1_Score, na.rm = TRUE), F1_Score),
Training_Time = ifelse(is.na(Training_Time), median(Training_Time, na.rm = TRUE), Training_Time)
)
ggp1 <- ggplot(data.frame(value=data$Accuracy), aes(x=value)) +
geom_histogram(fill="#FD0000", color="#E52521", alpha=0.9) +
ggtitle("Original data") +
xlab("Accuracy") + ylab("Frequency") +
theme_ipsum() +
theme(plot.title = element_text(size=15))
ggp2 <- ggplot(data.frame(value=data_imputados$Accuracy), aes(x=value)) +
geom_histogram(fill="#43B047", color="#049DCB", alpha=0.9) +
ggtitle("Reemplazado por Mediana") +
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()`).
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggp1 <- ggplot(data.frame(value=data$Precision), aes(x=value)) +
geom_histogram(fill="#FD0000", color="#E52521", alpha=0.9) +
ggtitle("Original data") +
xlab("Precision") + ylab("Frequency") +
theme_ipsum() +
theme(plot.title = element_text(size=15))
ggp2 <- ggplot(data.frame(value=data_imputados$Precision), aes(x=value)) +
geom_histogram(fill="#43B047", color="#049DCB", alpha=0.9) +
ggtitle("Reemplazado por Mediana") +
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()`).
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggp1 <- ggplot(data.frame(value=data$Recall), aes(x=value)) +
geom_histogram(fill="#FD0000", color="#E52521", alpha=0.9) +
ggtitle("Original data") +
xlab("Recall") + ylab("Frequency") +
theme_ipsum() +
theme(plot.title = element_text(size=15))
ggp2 <- ggplot(data.frame(value=data_imputados$Recall), aes(x=value)) +
geom_histogram(fill="#43B047", color="#049DCB", alpha=0.9) +
ggtitle("Reemplazado por Mediana") +
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()`).
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggp1 <- ggplot(data.frame(value=data$F1_Score), aes(x=value)) +
geom_histogram(fill="#FD0000", color="#E52521", 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=data_imputados$F1_Score), aes(x=value)) +
geom_histogram(fill="#43B047", color="#049DCB", alpha=0.9) +
ggtitle("Reemplazado por Mediana") +
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()`).
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggp1 <- ggplot(data.frame(value=data$Training_Time), aes(x=value)) +
geom_histogram(fill="#FD0000", color="#E52521", 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=data_imputados$Training_Time), aes(x=value)) +
geom_histogram(fill="#43B047", color="#049DCB", alpha=0.9) +
ggtitle("Mediana") +
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()`).
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Luego de haber tratado los valores NA. Ahora procederemos a identificar los valores atípicos y a realizar el adecuado tratamiento.
# Crear boxplot para Accuracy
gg_accuracy <- ggplot(data_imputados) +
aes(x = "", y = Accuracy) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("Accuracy") +
theme_minimal()
# Crear boxplot para Precision
gg_precision <- ggplot(data_imputados) +
aes(x = "", y = Precision) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("Precision") +
theme_minimal()
# Crear boxplot para Recall
gg_recall <- ggplot(data_imputados) +
aes(x = "", y = Recall) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("Recall") +
theme_minimal()
# Crear boxplot para F1_Score
gg_f1_score <- ggplot(data_imputados) +
aes(x = "", y = F1_Score) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("F1 Score") +
theme_minimal()
# Crear boxplot para Training Time
gg_training_time <- ggplot(data_imputados) +
aes(x = "", y = Training_Time) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("TrainingT") +
theme_minimal()
grid.arrange(gg_accuracy, gg_precision, gg_recall, gg_f1_score, gg_training_time, ncol = 5)
Primero se procederá a utilizar el método de Hampel para encontrar los valores atípicos. Luego, se aplicará Grubbs para ver si los valores máximos y minimos corresponden a outliers. Acto seguido, los valores encontrados se tratarán como NA y serán reemplazados por la mediana.
###### Accuracy (Hampel)
lower_bound <- median(data_imputados$Accuracy) - 3 * mad(data_imputados$Accuracy, constant = 1)
upper_bound <- median(data_imputados$Accuracy) + 3 * mad(data_imputados$Accuracy, constant = 1)
outlier_ind <- which(data_imputados$Accuracy < lower_bound | data$Accuracy > upper_bound)
###### Accuracy (Grubbs)
test <- grubbs.test(data_imputados$Accuracy)
test2 <- grubbs.test(data_imputados$Accuracy, opposite = TRUE)
test
##
## Grubbs test for one outlier
##
## data: data_imputados$Accuracy
## G = 9.72222, U = 0.83061, p-value < 2.2e-16
## alternative hypothesis: highest value 9.71807960083799 is an outlier
test2
##
## Grubbs test for one outlier
##
## data: data_imputados$Accuracy
## G = 0.40183, U = 0.99971, p-value = 1
## alternative hypothesis: lowest value 0.503781437489071 is an outlier
data_imputados$Accuracy[outlier_ind] <- NA
median_accuracy <- median(data_imputados$Accuracy, na.rm = TRUE)
data_imputados$Accuracy[is.na(data_imputados$Accuracy)] <- median_accuracy
gg_accuracy <- ggplot(data_imputados) +
aes(x = "", y = Accuracy) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("Accuracy") +
theme_minimal()
print(gg_accuracy)
Al volver a pintar el boxplot, se ve que ya no se tiene presencia de valores atípicos. A continuación,de manera iterativa, se aplicará el mismo método en las demás variables. #### Precision
###### Precision (Hampel)
lower_bound <- median(data_imputados$Precision, na.rm = TRUE) - 3 * mad(data_imputados$Precision, constant = 1, na.rm = TRUE)
upper_bound <- median(data_imputados$Precision, na.rm = TRUE) + 3 * mad(data_imputados$Precision, constant = 1, na.rm = TRUE)
outlier_ind <- which(data_imputados$Precision < lower_bound | data_imputados$Precision > upper_bound)
###### Precision (Grubbs)
test <- grubbs.test(data_imputados$Precision)
test2 <- grubbs.test(data_imputados$Precision, opposite = TRUE)
test
##
## Grubbs test for one outlier
##
## data: data_imputados$Precision
## G = 10.65938, U = 0.79638, p-value < 2.2e-16
## alternative hypothesis: highest value 9.73200811902357 is an outlier
test2
##
## Grubbs test for one outlier
##
## data: data_imputados$Precision
## G = 0.48720, U = 0.99957, p-value = 1
## alternative hypothesis: lowest value 0.401930958162567 is an outlier
# Reemplazo de outliers por NA y tratamiento
data_imputados$Precision[outlier_ind] <- NA
median_precision <- median(data_imputados$Precision, na.rm = TRUE)
data_imputados$Precision[is.na(data_imputados$Precision)] <- median_precision
# Visualización
gg_precision <- ggplot(data_imputados) +
aes(x = "", y = Precision) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("Precision") +
theme_minimal()
print(gg_precision)
###### Recall (Hampel)
lower_bound <- median(data_imputados$Recall, na.rm = TRUE) - 3 * mad(data_imputados$Recall, constant = 1, na.rm = TRUE)
upper_bound <- median(data_imputados$Recall, na.rm = TRUE) + 3 * mad(data_imputados$Recall, constant = 1, na.rm = TRUE)
outlier_ind <- which(data_imputados$Recall < lower_bound | data_imputados$Recall > upper_bound)
###### Recall (Grubbs)
test <- grubbs.test(data_imputados$Recall)
test2 <- grubbs.test(data_imputados$Recall, opposite = TRUE)
test
##
## Grubbs test for one outlier
##
## data: data_imputados$Recall
## G = 11.18902, U = 0.77564, p-value < 2.2e-16
## alternative hypothesis: highest value 9.36618227656069 is an outlier
test2
##
## Grubbs test for one outlier
##
## data: data_imputados$Recall
## G = 0.57746, U = 0.99940, p-value = 1
## alternative hypothesis: lowest value 0.30009428510314 is an outlier
# Reemplazo de outliers por NA y tratamiento
data_imputados$Recall[outlier_ind] <- NA
median_recall <- median(data_imputados$Recall, na.rm = TRUE)
data_imputados$Recall[is.na(data_imputados$Recall)] <- median_recall
# Visualización
gg_recall <- ggplot(data_imputados) +
aes(x = "", y = Recall) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("Recall") +
theme_minimal()
print(gg_recall)
###### F1_Score (Hampel)
lower_bound <- median(data_imputados$F1_Score, na.rm = TRUE) - 3 * mad(data_imputados$F1_Score, constant = 1, na.rm = TRUE)
upper_bound <- median(data_imputados$F1_Score, na.rm = TRUE) + 3 * mad(data_imputados$F1_Score, constant = 1, na.rm = TRUE)
outlier_ind <- which(data_imputados$F1_Score < lower_bound | data_imputados$F1_Score > upper_bound)
###### F1_Score (Grubbs)
test <- grubbs.test(data_imputados$F1_Score)
test2 <- grubbs.test(data_imputados$F1_Score, opposite = TRUE)
test
##
## Grubbs test for one outlier
##
## data: data_imputados$F1_Score
## G = 9.76785, U = 0.82901, p-value < 2.2e-16
## alternative hypothesis: highest value 9.37404866571267 is an outlier
test2
##
## Grubbs test for one outlier
##
## data: data_imputados$F1_Score
## G = 0.46580, U = 0.99961, p-value = 1
## alternative hypothesis: lowest value 0.40000698085322 is an outlier
# Reemplazo de outliers por NA y tratamiento
data_imputados$F1_Score[outlier_ind] <- NA
median_f1 <- median(data_imputados$F1_Score, na.rm = TRUE)
data_imputados$F1_Score[is.na(data_imputados$F1_Score)] <- median_f1
# Visualización
gg_f1 <- ggplot(data_imputados) +
aes(x = "", y = F1_Score) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("F1 Score") +
theme_minimal()
print(gg_f1)
#### Training_Time (Hampel)
lower_bound <- median(data_imputados$Training_Time, na.rm = TRUE) - 3 * mad(data_imputados$Training_Time, constant = 1, na.rm = TRUE)
upper_bound <- median(data_imputados$Training_Time, na.rm = TRUE) + 3 * mad(data_imputados$Training_Time, constant = 1, na.rm = TRUE)
outlier_ind <- which(data_imputados$Training_Time < lower_bound | data_imputados$Training_Time > upper_bound)
###### Training_Time (Grubbs)
test <- grubbs.test(data_imputados$Training_Time)
test2 <- grubbs.test(data_imputados$Training_Time, opposite = TRUE)
test
##
## Grubbs test for one outlier
##
## data: data_imputados$Training_Time
## G = 10.12941, U = 0.81612, p-value < 2.2e-16
## alternative hypothesis: highest value 46.9856257524936 is an outlier
test2
##
## Grubbs test for one outlier
##
## data: data_imputados$Training_Time
## G = 0.66003, U = 0.99922, p-value = 1
## alternative hypothesis: lowest value 0.103201614730368 is an outlier
# Reemplazo de outliers por NA y tratamiento
data_imputados$Training_Time[outlier_ind] <- NA
median_training_time <- median(data_imputados$Training_Time, na.rm = TRUE)
data_imputados$Training_Time[is.na(data_imputados$Training_Time)] <- median_training_time
# Visualización
gg_training_time <- ggplot(data_imputados) +
aes(x = "", y = Training_Time) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("Training Time") +
theme_minimal()
print(gg_training_time)
A manera de resumen se mostraran como quedaron los boxplot de las variables luego de tratar los outliers en cada una.
grid.arrange(gg_accuracy, gg_precision, gg_recall, gg_f1, gg_training_time, ncol = 5)
A continuación se procederá a analizar cada una de las variables que componen el dataset. Se hará teniendo en cuenta el estado original de la variable y el estado luego de la imputación.
# datos originales
summary(data$Accuracy)
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 0.5038 0.6236 0.7578 0.8779 0.8824 9.7181 39
# datos tratados
summary(data_imputados$Accuracy)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.5038 0.6368 0.7578 0.7519 0.8583 0.9997
Se puede ver que al mantenerse constante el valor de la mediana y la disminución de la media es muy probable que la eliminacion de los valores atipicos permite que los datos resultantes no esten sesgados por esos valores extremos mejorando la representación de los valores típicos.
# datos originales
coef_variacion <- (sd(data$Accuracy, na.rm = TRUE) / mean(data$Accuracy, na.rm = TRUE)) * 100
coef_variacion
## [1] 107.4343
# datos tratados
coef_variacion2 <- (sd(data_imputados$Accuracy) / mean(data_imputados$Accuracy)) * 100
coef_variacion2
## [1] 18.35139
En esta ocasión, el resultado menor de el coeficiente de variación para los datos imputados indica mayor homogeneidad en los datos y que son menos dispersos que como estaban originalmente.
gg_1 <- ggplot(data_imputados) +
aes(x = "", y = Accuracy) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("Accuracy") +
theme_minimal()
gg_2 <- ggplot(data) +
aes(x = "", y = Accuracy) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("Accuracy") +
theme_minimal()
grid.arrange(gg_2, gg_1, ncol = 2)
## Warning: Removed 39 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
densidad<-ggplot(data, aes(x = Accuracy)) +
geom_density(fill = "#0c4c8a", alpha = 0.7) +
labs(x = "Accuracy", y = "Densidad", title = "Gráfico de Densidad de Accuracy") +
theme_minimal()
densidad2<-ggplot(data_imputados, aes(x = Accuracy)) +
geom_density(fill = "#0c4c8a", alpha = 0.7) +
labs(x = "Accuracy", y = "Densidad", title = "Gráfico de Densidad de Accuracy") +
theme_minimal()
grid.arrange(densidad, densidad2, ncol = 2)
## Warning: Removed 39 rows containing non-finite outside the scale range
## (`stat_density()`).
Se pueden ver con estos gráficos que luego de tratar los datos ahora estan mucho más concentrados y la densidad no se extiende a valores atípicos.
# datos originales
summary(data$Precision)
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 0.4019 0.5632 0.7195 0.8129 0.8596 9.7320 19
# datos tratados
summary(data_imputados$Precision)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.4019 0.5672 0.7195 0.7064 0.8444 0.9990
Se puede ver que al mantenerse constante el valor de la mediana y la disminución de la media es muy probable que la eliminacion de los valores atipicos permite que los datos resultantes no esten sesgados por esos valores extremos mejorando la representación de los valores típicos.
# datos originales
coef_variacion <- (sd(data$Precision, na.rm = TRUE) / mean(data$Precision, na.rm = TRUE)) * 100
coef_variacion
## [1] 104.7427
# datos tratados
coef_variacion2 <- (sd(data_imputados$Precision) / mean(data_imputados$Precision)) * 100
coef_variacion2
## [1] 23.4662
En esta ocasión, el resultado menor de el coeficiente de variación para los datos imputados indica mayor homogeneidad en los datos y que son menos dispersos que como estaban originalmente.
gg_1 <- ggplot(data_imputados) +
aes(x = "", y = Precision) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("Precision") +
theme_minimal()
gg_2 <- ggplot(data) +
aes(x = "", y = Precision) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("Precision") +
theme_minimal()
grid.arrange(gg_2, gg_1, ncol = 2)
## Warning: Removed 19 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
densidad<-ggplot(data, aes(x = Precision)) +
geom_density(fill = "#0c4c8a", alpha = 0.7) +
labs(x = "Precision", y = "Densidad", title = "Gráfico de Densidad de Precision") +
theme_minimal()
densidad2<-ggplot(data_imputados, aes(x = Precision)) +
geom_density(fill = "#0c4c8a", alpha = 0.7) +
labs(x = "Precision", y = "Densidad", title = "Gráfico de Densidad de Precision") +
theme_minimal()
grid.arrange(densidad, densidad2, ncol = 2)
## Warning: Removed 19 rows containing non-finite outside the scale range
## (`stat_density()`).
Se pueden ver con estos gráficos que luego de tratar los datos ahora estan mucho más concentrados y la densidad no se extiende a valores atípicos.
# datos originales
summary(data$Recall)
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 0.3001 0.4819 0.6493 0.7486 0.8404 9.3662 20
# datos tratados
summary(data_imputados$Recall)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.3001 0.4926 0.6493 0.6492 0.8262 0.9985
Se puede ver que al mantenerse constante el valor de la mediana y la disminución de la media es muy probable que la eliminacion de los valores atipicos permite que los datos resultantes no esten sesgados por esos valores extremos mejorando la representación de los valores típicos.
# datos originales
coef_variacion <- (sd(data$Recall, na.rm = TRUE) / mean(data$Recall, na.rm = TRUE)) * 100
coef_variacion
## [1] 104.7911
# datos tratados
coef_variacion2 <- (sd(data_imputados$Recall) / mean(data_imputados$Recall)) * 100
coef_variacion2
## [1] 30.93555
En esta ocasión, el resultado menor de el coeficiente de variación para los datos imputados indica mayor homogeneidad en los datos y que son menos dispersos que como estaban originalmente.
gg_1 <- ggplot(data_imputados) +
aes(x = "", y = Recall) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("Recall") +
theme_minimal()
gg_2 <- ggplot(data) +
aes(x = "", y = Recall) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("Recall") +
theme_minimal()
grid.arrange(gg_2, gg_1, ncol = 2)
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
densidad<-ggplot(data, aes(x = Recall)) +
geom_density(fill = "#0c4c8a", alpha = 0.7) +
labs(x = "Recall", y = "Densidad", title = "Gráfico de Densidad de Recall") +
theme_minimal()
densidad2<-ggplot(data_imputados, aes(x = Recall)) +
geom_density(fill = "#0c4c8a", alpha = 0.7) +
labs(x = "Recall", y = "Densidad", title = "Gráfico de Densidad de Recall") +
theme_minimal()
grid.arrange(densidad, densidad2, ncol = 2)
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_density()`).
Se pueden ver con estos gráficos que luego de tratar los datos ahora estan mucho más concentrados y la densidad no se extiende a valores atípicos.
# datos originales
summary(data$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
# datos tratados
summary(data_imputados$F1_Score)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.4000 0.5579 0.7086 0.6970 0.8301 0.9993
Se puede ver que al mantenerse constante el valor de la mediana y la disminución de la media es muy probable que la eliminacion de los valores atipicos permite que los datos resultantes no esten sesgados por esos valores extremos mejorando la representación de los valores típicos.
# datos originales
coef_variacion <- (sd(data$F1_Score, na.rm = TRUE) / mean(data$F1_Score, na.rm = TRUE)) * 100
coef_variacion
## [1] 109.9297
# datos tratados
coef_variacion2 <- (sd(data_imputados$F1_Score) / mean(data_imputados$F1_Score)) * 100
coef_variacion2
## [1] 23.9237
En esta ocasión, el resultado menor de el coeficiente de variación para los datos imputados indica mayor homogeneidad en los datos y que son menos dispersos que como estaban originalmente.
gg_1 <- ggplot(data_imputados) +
aes(x = "", y = F1_Score) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("F1_Score") +
theme_minimal()
gg_2 <- ggplot(data) +
aes(x = "", y = F1_Score) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("F1_Score") +
theme_minimal()
grid.arrange(gg_2, gg_1, ncol = 2)
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
densidad<-ggplot(data, aes(x = F1_Score)) +
geom_density(fill = "#0c4c8a", alpha = 0.7) +
labs(x = "F1_Score", y = "Densidad", title = "Gráfico de Densidad de F1_Score") +
theme_minimal()
densidad2<-ggplot(data_imputados, aes(x = F1_Score)) +
geom_density(fill = "#0c4c8a", alpha = 0.7) +
labs(x = "F1_Score", y = "Densidad", title = "Gráfico de Densidad de F1_Score") +
theme_minimal()
grid.arrange(densidad, densidad2, ncol = 2)
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_density()`).
Se pueden ver con estos gráficos que luego de tratar los datos ahora estan mucho más concentrados y la densidad no se extiende a valores atípicos.
# datos originales
summary(data$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
# datos tratados
summary(data_imputados$Training_Time)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.1032 1.2982 2.4347 2.4835 3.6862 4.9978
Se puede ver que al mantenerse constante el valor de la mediana y la disminución de la media es muy probable que la eliminacion de los valores atipicos permite que los datos resultantes no esten sesgados por esos valores extremos mejorando la representación de los valores típicos.
# datos originales
coef_variacion <- (sd(data$Training_Time, na.rm = TRUE) / mean(data$Training_Time, na.rm = TRUE)) * 100
coef_variacion
## [1] 147.9032
# datos tratados
coef_variacion2 <- (sd(data_imputados$Training_Time) / mean(data_imputados$Training_Time)) * 100
coef_variacion2
## [1] 55.49392
En esta ocasión, el resultado menor de el coeficiente de variación para los datos imputados indica mayor homogeneidad en los datos y que son menos dispersos que como estaban originalmente.
gg_1 <- ggplot(data_imputados) +
aes(x = "", y = Training_Time) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("TrainingTime") +
theme_minimal()
gg_2 <- ggplot(data) +
aes(x = "", y = Training_Time) +
geom_boxplot(fill = "#0c4c8a") +
ggtitle("TrainingTime") +
theme_minimal()
grid.arrange(gg_2, gg_1, ncol = 2)
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
densidad<-ggplot(data, aes(x = Training_Time)) +
geom_density(fill = "#0c4c8a", alpha = 0.7) +
labs(x = "TrainingTime", y = "Densidad", title = "Gráfico de Densidad de TrainingTime") +
theme_minimal()
densidad2<-ggplot(data_imputados, aes(x = Training_Time)) +
geom_density(fill = "#0c4c8a", alpha = 0.7) +
labs(x = "TrainingTime", y = "Densidad", title = "Gráfico de Densidad TrainingTime") +
theme_minimal()
grid.arrange(densidad, densidad2, ncol = 2)
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_density()`).
Se pueden ver con estos gráficos que luego de tratar los datos ahora estan mucho más concentrados y la densidad no se extiende a valores atípicos.
Primero verificaremos las categorías presentes en esta variable. Luego validaremos si hay valores NA.
table(data$Algorithm)
##
## K-Means Neural Network Random Forest SVM
## 163 135 126 136
NAS_TL<-is.na(data$Algorithm)
data[NAS_TL,]
## # A tibble: 0 × 10
## # ℹ 10 variables: Algorithm <chr>, Framework <chr>, Problem_Type <chr>,
## # Dataset_Type <chr>, Accuracy <dbl>, Precision <dbl>, Recall <dbl>,
## # F1_Score <dbl>, Training_Time <dbl>, Date <dbl>
Dado que no encontramos NA, procederemos a graficar.
data_summary <- data %>%
count(Algorithm) %>%
mutate(Percentage = n / sum(n) * 100)
data_summary <- data %>%
count(Algorithm) %>%
mutate(Percentage = n / sum(n) * 100)
ggplot(data_summary, aes(x = Algorithm, y = n)) +
geom_bar(stat = "identity", fill = "#0073B2") +
geom_text(aes(label = paste0(round(Percentage, 1), "%")),
vjust = -0.5, color = "black") +
ggtitle("Frecuencia de Algorithm") +
xlab("Algorithm") +
ylab("Frecuencia") +
theme_minimal()
Vemos en este gráfico que la categoría con menor representación es Random Forest y la de mayor es K-Means. Neural Network y SVM tienen cantidades parecidas.
Primero verificaremos las categorías presentes en esta variable. Luego validaremos si hay valores NA.
table(data$Framework)
##
## Keras PyTorch Scikit-learn TensorFlow
## 124 135 134 167
NAS_TL<-is.na(data$Framework)
data[NAS_TL,]
## # A tibble: 0 × 10
## # ℹ 10 variables: Algorithm <chr>, Framework <chr>, Problem_Type <chr>,
## # Dataset_Type <chr>, Accuracy <dbl>, Precision <dbl>, Recall <dbl>,
## # F1_Score <dbl>, Training_Time <dbl>, Date <dbl>
Dado que no encontramos NA, procederemos a graficar.
framework_summary <- data %>%
count(Framework) %>%
mutate(Percentage = n / sum(n) * 100)
ggplot(framework_summary, aes(x = Framework, y = n)) +
geom_bar(stat = "identity", fill = "#0073B2") +
geom_text(aes(label = paste0(round(Percentage, 1), "%")),
vjust = -0.5, color = "black") +
ggtitle("Frecuencia de Framework") +
xlab("Framework") +
ylab("Frecuencia") +
theme_minimal()
Vemos en este gráfico que la categoría con mayor representación es TensoFlow y la de menor es Keras. PyTorch y Scikit-learn tienen cantidades parecidas.
Primero verificaremos las categorías presentes en esta variable. Luego validaremos si hay valores NA.
table(data$Problem_Type)
##
## Classification Clustering Regression
## 175 196 189
NAS_TL<-is.na(data$Problem_Type)
data[NAS_TL,]
## # A tibble: 0 × 10
## # ℹ 10 variables: Algorithm <chr>, Framework <chr>, Problem_Type <chr>,
## # Dataset_Type <chr>, Accuracy <dbl>, Precision <dbl>, Recall <dbl>,
## # F1_Score <dbl>, Training_Time <dbl>, Date <dbl>
Dado que no encontramos NA, procederemos a graficar.
problem_type_summary <- data %>%
count(Problem_Type) %>%
mutate(Percentage = n / sum(n) * 100)
ggplot(problem_type_summary, aes(x = Problem_Type, y = n)) +
geom_bar(stat = "identity", fill = "#0073B2") +
geom_text(aes(label = paste0(round(Percentage, 1), "%")),
vjust = -0.5, color = "black") +
ggtitle("Frecuencia de Problem_Type") +
xlab("Problem_Type") +
ylab("Frecuencia") +
theme_minimal()
Vemos en este gráfico que la categoría con mayor representación es Clustering y la de menor es Classification.
Primero verificaremos las categorías presentes en esta variable. Luego validaremos si hay valores NA.
table(data$Dataset_Type)
##
## Image Tabular Text Time Series
## 157 136 143 124
NAS_TL<-is.na(data$Dataset_Type)
data[NAS_TL,]
## # A tibble: 0 × 10
## # ℹ 10 variables: Algorithm <chr>, Framework <chr>, Problem_Type <chr>,
## # Dataset_Type <chr>, Accuracy <dbl>, Precision <dbl>, Recall <dbl>,
## # F1_Score <dbl>, Training_Time <dbl>, Date <dbl>
Dado que no encontramos NA, procederemos a graficar.
dataset_type_summary <- data %>%
count(Dataset_Type) %>%
mutate(Percentage = n / sum(n) * 100)
ggplot(dataset_type_summary, aes(x = Dataset_Type, y = n)) +
geom_bar(stat = "identity", fill = "#0073B2") +
geom_text(aes(label = paste0(round(Percentage, 1), "%")),
vjust = -0.5, color = "black") +
xlab("Dataset_Type") +
ylab("Frecuencia") +
theme_minimal()
Vemos en este gráfico que la categoría con menor representación es time series y la de mayor es Image.
ggplot(data_imputados, aes(x = Algorithm, y = Accuracy)) +
geom_boxplot(fill = "#0c4c8a") +
theme_minimal()
ggplot(data_imputados, aes(x = Framework, y = Accuracy)) +
geom_boxplot(fill = "#0c4c8a") +
theme_minimal()
ggplot(data_imputados, aes(x = Problem_Type, y = Accuracy)) +
geom_boxplot(fill = "#0c4c8a") +
theme_minimal()
ggplot(data_imputados, aes(x = Dataset_Type, y = Accuracy)) +
geom_boxplot(fill = "#0c4c8a") +
theme_minimal()
Para este primer análisis se comparó la precisión frente a variables como el tipo de problema, el tipo de dataset, el framework y el algoritmo. En el caso de los algoritmos, vemos que las medianas son muy similares, por tanto no hay diferencias muy grandes entre el accuracy de cada algoritmo. Lo mismo vemos para el framework, en este caso la caja de tensorflow es más grande por lo que podríamos pensar que los valores acá pueden estar más dispersos. Para el tipo de problema vemos que tambien vemos medianas similares, pero hay sesgos notorios en problemas de clasificación y regresión, mientras que según el dataset hay una ligera diferencia en la mediana del text, apareciendo un poco por encima de las demás.
ggplot(data_imputados, aes(x = Algorithm, fill = Framework)) +
geom_bar(position = "fill") +
theme_minimal()
ggplot(data_imputados, aes(x = Algorithm, fill = Dataset_Type)) +
geom_bar(position = "fill") +
theme_minimal()
ggplot(data_imputados, aes(x = Algorithm, fill = Problem_Type)) +
geom_bar(position = "fill") +
theme_minimal()
En esta ocasión comparamos el comportamiento de la variable algoritmo con el framework, el tipo de dataset, y el tipo de problema. Frente al framework tenemos que Tensorflow está distribuido similarmente entre los diferentes algoritmos, mientras que para PyTorch se usa más para SVM y poco para K-Means. Por otro lado, en Keras tambien vemos una diferencia considerable entre algoritmos SVM y Neural Network o K-Means que casi duplica su barra. Frente al tipo de dataset, tenemos que las time series se distribuyen similarmente, pero para los tipo Tabular, vemos que las K-means o Random Forest se presentan más seguido que las SVM. Finalmente, frente al tipo de problemas vemos que es común encontrar relacionadas las Regressions con Neural Network o SVM, Clustering con K-Means y Classification con Neural Network.
ggplot(data_imputados, aes(x = Accuracy, y = Training_Time)) +
geom_point() +
geom_smooth(method = "lm", se = FALSE, color = "blue") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
ggplot(data_imputados, aes(x = Precision, y = Training_Time)) +
geom_point() +
geom_smooth(method = "lm", se = FALSE, color = "blue") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
ggplot(data_imputados, aes(x = Recall, y = Training_Time)) +
geom_point() +
geom_smooth(method = "lm", se = FALSE, color = "blue") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
ggplot(data_imputados, aes(x = F1_Score, y = Training_Time)) +
geom_point() +
geom_smooth(method = "lm", se = FALSE, color = "blue") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
Para este caso, comparamos la variable Training_Time con las demás variables numéricas. En este caso vemos que para ninguna de las comparaciones veremos una tendencia clara que permita concluir que están estrechamente relacionadas entre si, pues los puntos estan muy dispersos y la linea de regresión no tiene una pendiente muy marcada.
Para realizar las pruebas analíticas primero determinaremos la normalidad de las variables numéricas.
normality_test <- function(data) {
shapiro_test <- shapiro.test(data)
return(shapiro_test$p.value > 0.05)
}
variables <- c("Accuracy", "Precision", "Recall", "F1_Score", "Training_Time")
normality_results <- tibble(
Variable = variables,
Normal_Distribution = sapply(variables, function(v) normality_test(data_imputados[[v]]))
)
normality_results
## # A tibble: 5 × 2
## Variable Normal_Distribution
## <chr> <lgl>
## 1 Accuracy FALSE
## 2 Precision FALSE
## 3 Recall FALSE
## 4 F1_Score FALSE
## 5 Training_Time FALSE
Al confirmar que no tenemos distribuciones normales en las variables numéricas se procederá a aplicar pruebas como Kruskal-Wallis, para las categóricas vs numéricas, Chi-cuadrado para categóricas vs categóricas y Correlación de Spearman para numérica vs numérica. ##### Kruskal-Wallis ##### Algorithm vs Accuracy
kruskal.test(Accuracy ~ Algorithm, data = data_imputados)
##
## Kruskal-Wallis rank sum test
##
## data: Accuracy by Algorithm
## Kruskal-Wallis chi-squared = 1.4043, df = 3, p-value = 0.7045
kruskal.test(Accuracy ~ Framework, data = data_imputados)
##
## Kruskal-Wallis rank sum test
##
## data: Accuracy by Framework
## Kruskal-Wallis chi-squared = 1.5348, df = 3, p-value = 0.6743
kruskal.test(Accuracy ~ Problem_Type, data = data_imputados)
##
## Kruskal-Wallis rank sum test
##
## data: Accuracy by Problem_Type
## Kruskal-Wallis chi-squared = 5.6331, df = 2, p-value = 0.05981
kruskal.test(Accuracy ~ Dataset_Type, data = data_imputados)
##
## Kruskal-Wallis rank sum test
##
## data: Accuracy by Dataset_Type
## Kruskal-Wallis chi-squared = 6.5511, df = 3, p-value = 0.08767
Vemos valores de 1.4043, 1.5348, 1.4043 y 6.5511. Los 3 primeros valores nos permiten pensar que no hay diferencias significativas entre los diferentes algoritmos, frameworks y tipos de problema. Sin embargo, entre los diferentes tipos de dataset tenemos un p-value más alto, por lo que podemos pensar que existen diferencias en el Accuracy según el tipo de dataset.
chisq.test(table(data_imputados$Algorithm, data_imputados$Framework))
##
## Pearson's Chi-squared test
##
## data: table(data_imputados$Algorithm, data_imputados$Framework)
## X-squared = 5.6463, df = 9, p-value = 0.7747
chisq.test(table(data_imputados$Algorithm, data_imputados$Dataset_Type))
##
## Pearson's Chi-squared test
##
## data: table(data_imputados$Algorithm, data_imputados$Dataset_Type)
## X-squared = 4.9299, df = 9, p-value = 0.8404
chisq.test(table(data_imputados$Algorithm, data_imputados$Problem_Type))
##
## Pearson's Chi-squared test
##
## data: table(data_imputados$Algorithm, data_imputados$Problem_Type)
## X-squared = 6.5396, df = 6, p-value = 0.3655
Los resultados de estas chi-cuadrado nos permiten concluir que no hay asociación significativa entre ninguno de estos pares de variables. Por tanto los algoritmos no influyen significativamente entre el tipo de dataset, problema o framework.
cor.test(data_imputados$Accuracy, data_imputados$Training_Time, method = "spearman")
## Warning in cor.test.default(data_imputados$Accuracy,
## data_imputados$Training_Time, : Cannot compute exact p-value with ties
##
## Spearman's rank correlation rho
##
## data: data_imputados$Accuracy and data_imputados$Training_Time
## S = 30398237, p-value = 0.3622
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
## rho
## -0.03857282
cor.test(data_imputados$Precision, data_imputados$Training_Time, method = "spearman")
## Warning in cor.test.default(data_imputados$Precision,
## data_imputados$Training_Time, : Cannot compute exact p-value with ties
##
## Spearman's rank correlation rho
##
## data: data_imputados$Precision and data_imputados$Training_Time
## S = 28219396, p-value = 0.3969
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
## rho
## 0.03586852
cor.test(data_imputados$Recall, data_imputados$Training_Time, method = "spearman")
## Warning in cor.test.default(data_imputados$Recall,
## data_imputados$Training_Time, : Cannot compute exact p-value with ties
##
## Spearman's rank correlation rho
##
## data: data_imputados$Recall and data_imputados$Training_Time
## S = 30938845, p-value = 0.1777
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
## rho
## -0.05704299
Al observar los coeficientes de correlación vemos que no hay evidencia para suficiente para afirmar que haya relación entre las variables comparadas previamente.
Luego de haber hecho una exploración general del dataset, se retomará
la pregunta planteada en la introducción del presente trabajo.
¿Qué frameworks producen los modelos más precisos en cada tipo
de problema?.
Primero, procederemos a graficar las variables framework, precision y
Problem_Type, luego realizaremos una prueba Krustal-Wallis
summary_accuracy <- data_imputados %>%
group_by(Framework, Problem_Type) %>%
summarise(mean_accuracy = mean(Accuracy, na.rm = TRUE)) %>%
arrange(Problem_Type, desc(mean_accuracy))
## `summarise()` has grouped output by 'Framework'. You can override using the
## `.groups` argument.
ggplot(summary_accuracy, aes(x = Framework, y = mean_accuracy, fill = Problem_Type)) +
geom_bar(stat = "identity", position = position_dodge()) +
labs(title = "Precisión Media por Framework y Tipo de Problema",
x = "Framework", y = "Precisión Media") +
theme_minimal()
data_filtered <- data_imputados %>% filter(Problem_Type == "Classification")
data_filtered2 <- data_imputados %>% filter(Problem_Type == "Clustering")
data_filtered3 <- data_imputados %>% filter(Problem_Type == "Regression")
# Realizar la prueba de Kruskal-Wallis
kruskal_test <- kruskal.test(Accuracy ~ Framework, data = data_filtered)
kruskal_test2 <- kruskal.test(Accuracy ~ Framework, data = data_filtered2)
kruskal_test3 <- kruskal.test(Accuracy ~ Framework, data = data_filtered3)
print(kruskal_test)
##
## Kruskal-Wallis rank sum test
##
## data: Accuracy by Framework
## Kruskal-Wallis chi-squared = 0.77939, df = 3, p-value = 0.8544
print(kruskal_test2)
##
## Kruskal-Wallis rank sum test
##
## data: Accuracy by Framework
## Kruskal-Wallis chi-squared = 0.24542, df = 3, p-value = 0.9699
print(kruskal_test3)
##
## Kruskal-Wallis rank sum test
##
## data: Accuracy by Framework
## Kruskal-Wallis chi-squared = 5.537, df = 3, p-value = 0.1364
# Realizar la prueba de Kruskal-Wallis
Las pruebas anteriores concluyen, de manera general, que no hay diferencias significativas entre uno u otro framework. Sin embargo, si miramos detenidamente el gráfico, se puede pensar que, para problemas de tipo Regression, sería óptimo usar Scikit-learn, pues tiene la media más alta de Accuracy entre todos los frameworks, mientras que Clustering o Classification no podríamos seleccionar uno sobre otro, concidiendo así con la prueba analítica realizada.