Recursos/Librerías

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2     
## ── 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
library(ggplot2)
library(readxl)
require(tibble)
library(readr)
library(dplyr)
library(Amelia)
## 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
## ##
library(Rcpp)
library(knitr)
library(kableExtra)
## 
## Adjuntando el paquete: 'kableExtra'
## 
## The following object is masked from 'package:dplyr':
## 
##     group_rows
library(maps)
## 
## Adjuntando el paquete: 'maps'
## 
## The following object is masked from 'package:purrr':
## 
##     map
library(psych)
## 
## Adjuntando el paquete: 'psych'
## 
## The following objects are masked from 'package:ggplot2':
## 
##     %+%, alpha
library(countrycode)
library(e1071)
library(reshape2)
## 
## Adjuntando el paquete: 'reshape2'
## 
## The following object is masked from 'package:tidyr':
## 
##     smiths
library(VIM)
## Cargando paquete requerido: colorspace
## Cargando paquete requerido: grid
## VIM is ready to use.
## 
## Suggestions and bug-reports can be submitted at: https://github.com/statistikat/VIM/issues
## 
## Adjuntando el paquete: 'VIM'
## 
## The following object is masked from 'package:datasets':
## 
##     sleep
library(mice)
## 
## Adjuntando el paquete: 'mice'
## 
## The following object is masked from 'package:stats':
## 
##     filter
## 
## The following objects are masked from 'package:base':
## 
##     cbind, rbind
library(naniar)
library(gridExtra)
## 
## Adjuntando el paquete: 'gridExtra'
## 
## The following object is masked from 'package:dplyr':
## 
##     combine
library(lattice)
library(EnvStats)
## 
## Adjuntando el paquete: 'EnvStats'
## 
## The following objects are masked from 'package:e1071':
## 
##     kurtosis, skewness
## 
## The following objects are masked from 'package:stats':
## 
##     predict, predict.lm
library(ggcorrplot)
library(psych)

Introducción

La Inteligencia Artificial (IA) ha revolucionado numerosos campos en los últimos años, convirtiéndose en una herramienta clave para resolver problemas complejos y optimizar procesos en una amplia variedad de industrias. En el núcleo de la IA se encuentran los algoritmos que permiten a las máquinas aprender y tomar decisiones basadas en grandes volúmenes de datos. Estos algoritmos, cuando son entrenados adecuadamente, pueden clasificar datos, hacer predicciones y encontrar patrones en situaciones donde las soluciones tradicionales no son suficientes. Sin embargo, la elección del algoritmo adecuado, el framework de desarrollo y el tipo de problema a abordar juegan un papel crucial en la efectividad y eficiencia de los modelos de IA.

Este trabajo tiene como propósito realizar un Análisis Exploratorio de Datos (EDA) sobre un conjunto de datos sintético relacionado con problemas de Inteligencia Artificial (IA). El dataset fue generado con fines educativos y contiene información sobre diversos algoritmos de IA, frameworks, tipos de problemas abordados, y métricas de desempeño como la precisión y el tiempo de entrenamiento. A través de este análisis, se busca obtener una mejor comprensión del comportamiento de los modelos y su desempeño en diferentes contextos.

El análisis se centrará en investigar el tipo de problema que presenta el menor tiempo de entrenamiento sin comprometer la precisión, utilizando específicamente el algoritmo Random Forest y el framework Scikit-learn. Además, se hará un análisis de la distribución de las variables categóricas, se revisarán los valores faltantes y se identificarán outliers que podrían influir en los resultados del análisis. Este enfoque permitirá explorar las diferencias entre estos tipos de problemas y cómo se comportan en términos de tiempo y precisión, aportando valiosa información para la optimización de los modelos en aplicaciones prácticas de IA.

Objetivo del Análisis

El objetivo de este Análisis Exploratorio de Datos (EDA) es responder a la pregunta: ¿Qué tipo de problema logra el menor tiempo de entrenamiento sin comprometer la precisión, utilizando el algoritmo Random Forest y el framework Scikit-learn?. Para lograrlo, se analizarán los patrones de comportamiento de los modelos de inteligencia artificial en función de estas variables clave, evaluando el equilibrio entre el tiempo de entrenamiento y la precisión alcanzada por cada tipo de problema.

Además, se llevará a cabo una revisión exhaustiva de los valores faltantes, se detectarán y tratarán outliers, y se aplicarán técnicas de limpieza de datos, todo con el fin de preparar adecuadamente el conjunto de datos, con el fin de asegurar que la calidad del conjunto de datos sea adecuada para futuros análisis.

Carga y Estructura del Dataset

Inicialmente, los datos estaban almacenados en un archivo Excel (.xlsx), por lo que se intentó leer utilizando la librería readxl, la cual permite manejar archivos en este formato. Sin embargo, parecía vacío al cargarse en R. Debido a esta situación, se decidió convertir el archivo de Excel a formato CSV para garantizar su correcta lectura y manipulación.

# Cargar la base de datos en la variable "datos"
datos <- read.csv(file.choose(), 
        sep=",", 
        header=TRUE, 
        fileEncoding = "UTF-8")

# Inspección de la estructura del dataset
library(kableExtra)
kable(datos[1:20, ], caption= "Tabla 1: DataSet ") %>%
  kable_styling(full_width = F) %>%
  column_spec(2, width = "20em") %>%
  scroll_box(width = "900px", height = "450px")
Tabla 1: DataSet
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

Dimensiones

dim(datos)
## [1] 560  10

El resultado muestra un data frame con 560 observaciones(filas) y 10 variables(columnas). Este tamaño de muestra es suficiente para realizar un análisis significativo, ya que permite identificar patrones y relaciones en los datos.

Nombres de las Variables y Tipo de Dato (Estructura):

names(datos)
##  [1] "Algorithm"     "Framework"     "Problem_Type"  "Dataset_Type" 
##  [5] "Accuracy"      "Precision"     "Recall"        "F1_Score"     
##  [9] "Training_Time" "Date"
sapply(datos, class)
##     Algorithm     Framework  Problem_Type  Dataset_Type      Accuracy 
##   "character"   "character"   "character"   "character"     "numeric" 
##     Precision        Recall      F1_Score Training_Time          Date 
##     "numeric"     "numeric"     "numeric"     "numeric"   "character"

Clasificación de las Variables:

Cualitativas Categóricas:

  • Algorithm: Indica el tipo de algoritmo de inteligencia artificial utilizado.

  • Framework: Indica el framework o biblioteca utilizada para la implementación del modelo.

  • Problem_Type: Identifica el tipo de problema abordado por el modelo

  • Dataset_Type: Describe el tipo de datos utilizados en el entrenamiento del modelo.

  • Date: Representa la fecha en la que se realizó la evaluación del modelo.

Cuantitativas Continuas:

  • Accuracy: Mide la precisión del modelo.

  • Precision: Mide la precisión del modelo en términos de la fracción de positivos verdaderos sobre el total de positivos predichos.

  • Recall: Mide la capacidad del modelo para identificar correctamente los positivos verdaderos.

  • F1_Score: Mide el balance entre precisión y recall, medida armónica de ambas métricas.

  • Training_Time: Indica el tiempo de entrenamiento del modelo en horas.

str(datos)
## 'data.frame':    560 obs. of  10 variables:
##  $ Algorithm    : chr  "SVM" "K-Means" "Neural Network" "SVM" ...
##  $ Framework    : chr  "Scikit-learn" "Keras" "Keras" "Keras" ...
##  $ Problem_Type : chr  "Regression" "Clustering" "Clustering" "Clustering" ...
##  $ Dataset_Type : chr  "Time Series" "Time Series" "Image" "Text" ...
##  $ Accuracy     : num  0.662 0.744 0.885 0.842 0.723 ...
##  $ Precision    : num  0.693 0.49 0.595 0.842 0.686 ...
##  $ Recall       : num  NA 0.877 0.969 0.875 0.301 ...
##  $ F1_Score     : num  0.443 0.441 0.964 0.704 0.646 ...
##  $ Training_Time: num  4.98 NA 3.28 4.04 3.6 ...
##  $ Date         : chr  "2023-03-08 11:26:21" "2023-03-09 11:26:21" "2023-03-10 11:26:21" "2023-03-11 11:26:21" ...

A continuación se presenta la tabala de operacionalización de variables utilizando el paquete knitr, que organiza la clasificación de las variables según su tipo y subtipo:

# Crear un nuevo dataframe para la tabla de operacionalización
operacionalizacion <- data.frame(
  Variable = c("Algorithm", "Framework", "Problem_Type", "Dataset_Type", "Accuracy", 
               "Precision", "Recall", "F1_Score", "Training_Time", "Date"),
  Naturaleza = c("Cualitativa/Categórica", "Cualitativa/Categórica", "Cualitativa/Categórica", 
                 "Cualitativa/Categórica", "Cuantitativa/Numerica", "Cuantitativa/Numerica", 
                 "Cuantitativa/Numerica", "Cuantitativa/Numerica", "Cuantitativa/Numerica", 
                 "Cuantitativa/Numerica"),
  Nivel_de_Medicion = c("Nominal", "Nominal", "Nominal", "Nominal", "Continua de razón", 
                        "Continua de razón", "Continua de razón", "Continua de razón", 
                        "Continua de razón", "Intervalo (ordinal)"),
  Criterio_Clasificacion = c(
    "Algoritmo de IA usado (e.g., SVM, K-Means, Neural Network, Random Forest).", 
    "Framework o biblioteca utilizada (e.g., Scikit-learn, Keras, TensorFlow, PyTorch).", 
    "Tipo de problema abordado por el algoritmo (Clasificación, Regresión, Clustering).", 
    "Tipo de datos (Image, Text, Tabular, Time Series).", 
    "Medida de la precisión del modelo (valor entre 0 y 1).", 
    "Proporción de positivos verdaderos entre todos los positivos predichos.", 
    "Proporción de positivos verdaderos correctamente identificados.", 
    "Medida armónica entre la precisión y el recall del modelo.", 
    "Tiempo de entrenamiento del modelo en horas.", 
    "Fecha en la que se realizó la evaluación del modelo."
  ),
  stringsAsFactors = FALSE # Para evitar que se conviertan en factores
)

# Generar la tabla estilizada en RMarkdown
operacionalizacion %>%
  kbl(caption = "Tabla de Operacionalización de Variables") %>%
  kable_styling(full_width = F, bootstrap_options = c("striped", "hover", "condensed", "responsive"), 
                font_size = 14, position = "center") %>%
  row_spec(0, bold = TRUE, color = "white", background = "#0073C2FF") %>%  # Encabezado con estilo
  row_spec(1:nrow(operacionalizacion), background = "lightgray")  # Alternar color de filas
Tabla de Operacionalización de Variables
Variable Naturaleza Nivel_de_Medicion Criterio_Clasificacion
Algorithm Cualitativa/Categórica Nominal Algoritmo de IA usado (e.g., SVM, K-Means, Neural Network, Random Forest).
Framework Cualitativa/Categórica Nominal Framework o biblioteca utilizada (e.g., Scikit-learn, Keras, TensorFlow, PyTorch).
Problem_Type Cualitativa/Categórica Nominal Tipo de problema abordado por el algoritmo (Clasificación, Regresión, Clustering).
Dataset_Type Cualitativa/Categórica Nominal Tipo de datos (Image, Text, Tabular, Time Series).
Accuracy Cuantitativa/Numerica Continua de razón Medida de la precisión del modelo (valor entre 0 y 1).
Precision Cuantitativa/Numerica Continua de razón Proporción de positivos verdaderos entre todos los positivos predichos.
Recall Cuantitativa/Numerica Continua de razón Proporción de positivos verdaderos correctamente identificados.
F1_Score Cuantitativa/Numerica Continua de razón Medida armónica entre la precisión y el recall del modelo.
Training_Time Cuantitativa/Numerica Continua de razón Tiempo de entrenamiento del modelo en horas.
Date Cuantitativa/Numerica Intervalo (ordinal) Fecha en la que se realizó la evaluación del modelo.

Resumen estadístico

En esta sección se presenta el Resumen Estadístico del dataset. El análisis de las variables cualitativas se realiza mediante tablas de frecuencia y diagramas de barras, que muestran la distribución de las categorías en cada una. Esto es esencial para identificar cómo se distribuyen las observaciones entre las distintas categorías.

Por otro lado, el análisis de las variables cuantitativas incluye un resumen estadístico que muestra medidas como la media, mediana, mínimo, máximo y los cuartiles. Estas medidas son clave para comprender la dispersión y tendencia central de los datos numéricos.

Es importante destacar que la variable “Date” no fue considerada para este análisis exploratorio, ya que su relevancia en el contexto no era crítica para los objetivos actuales.

# Resumen estadístico detallado
describe(datos)
##               vars   n   mean     sd median trimmed    mad min    max  range
## Algorithm*       1 560   2.42   1.15   2.00    2.40   1.48 1.0   4.00   3.00
## Framework*       2 560   2.61   1.13   3.00    2.64   1.48 1.0   4.00   3.00
## Problem_Type*    3 560   2.02   0.81   2.00    2.03   1.48 1.0   3.00   2.00
## Dataset_Type*    4 560   2.42   1.12   2.00    2.40   1.48 1.0   4.00   3.00
## Accuracy         5 521   0.88   0.94   0.76    0.76   0.19 0.5   9.72   9.21
## Precision        6 541   0.81   0.85   0.72    0.71   0.22 0.4   9.73   9.33
## Recall           7 540   0.75   0.78   0.65    0.66   0.27 0.3   9.37   9.07
## F1_Score         8 540   0.81   0.89   0.71    0.70   0.22 0.4   9.37   8.97
## Training_Time    9 540   2.99   4.42   2.43    2.52   1.87 0.1  46.99  46.88
## Date*           10 560 280.50 161.80 280.50  280.50 207.56 1.0 560.00 559.00
##                skew kurtosis   se
## Algorithm*     0.10    -1.42 0.05
## Framework*    -0.12    -1.38 0.05
## Problem_Type* -0.05    -1.46 0.03
## Dataset_Type*  0.08    -1.36 0.05
## Accuracy       7.32    55.40 0.04
## Precision      7.96    69.45 0.04
## Recall         7.27    59.60 0.03
## F1_Score       7.47    59.15 0.04
## Training_Time  7.63    66.83 0.19
## Date*          0.00    -1.21 6.84

Variables CUALITATIVAS/CATEGÓRICAS

# Función para calcular las frecuencias absolutas, relativas, acumuladas y la moda
resumen_categorico <- function(variable, nombre_variable) {
  
  # Calcular la tabla de frecuencias absolutas
  frecuencias_absolutas <- table(variable)
  # Calcular la frecuencia relativa
  frecuencias_relativas <- prop.table(frecuencias_absolutas) * 100
  # Calcular la frecuencia acumulada
  frecuencias_acumuladas <- cumsum(frecuencias_absolutas)
  # Identificar la moda
  moda <- names(frecuencias_absolutas[frecuencias_absolutas == max(frecuencias_absolutas)])
  cantidad_moda <- max(frecuencias_absolutas)
  # Crear el dataframe con el resumen
  resumen_df <- data.frame(
    Categoria = names(frecuencias_absolutas),
    Frecuencia_Absoluta = as.numeric(frecuencias_absolutas),
    Frecuencia_Relativa = round(as.numeric(frecuencias_relativas), 2),
    Frecuencia_Acumulada = as.numeric(frecuencias_acumuladas)
  )
  # Añadir la moda como fila adicional
  resumen_df <- resumen_df %>%
    add_row(Categoria = paste("Moda:", moda),
            Frecuencia_Absoluta = cantidad_moda,
            Frecuencia_Relativa = NA,  # No aplica para la moda
            Frecuencia_Acumulada = NA)  # No aplica para la moda
  # Crear una tabla estilizada con kable
  tabla_kable <- resumen_df %>%
    kbl(caption = paste("Resumen de Frecuencias para", nombre_variable), digits = 2, align = "c") %>%
    kable_styling(full_width = F, bootstrap_options = c("striped", "hover", "condensed"), 
                  font_size = 12, position = "center") %>%
    column_spec(1, bold = TRUE, background = "lightblue")
  tabla_kable %>%
    row_spec(nrow(resumen_df), bold = TRUE, color = "white", background = "red")
}

# Aplicar la función a las variables categóricas
resumen_categorico(datos$Algorithm, "Algorithm")
Resumen de Frecuencias para Algorithm
Categoria Frecuencia_Absoluta Frecuencia_Relativa Frecuencia_Acumulada
K-Means 163 29.11 163
Neural Network 135 24.11 298
Random Forest 126 22.50 424
SVM 136 24.29 560
Moda: K-Means 163 NA NA
resumen_categorico(datos$Framework, "Framework")
Resumen de Frecuencias para Framework
Categoria Frecuencia_Absoluta Frecuencia_Relativa Frecuencia_Acumulada
Keras 124 22.14 124
PyTorch 135 24.11 259
Scikit-learn 134 23.93 393
TensorFlow 167 29.82 560
Moda: TensorFlow 167 NA NA
resumen_categorico(datos$Problem_Type, "Problem Type")
Resumen de Frecuencias para Problem Type
Categoria Frecuencia_Absoluta Frecuencia_Relativa Frecuencia_Acumulada
Classification 175 31.25 175
Clustering 196 35.00 371
Regression 189 33.75 560
Moda: Clustering 196 NA NA
resumen_categorico(datos$Dataset_Type, "Dataset Type")
Resumen de Frecuencias para Dataset Type
Categoria Frecuencia_Absoluta Frecuencia_Relativa Frecuencia_Acumulada
Image 157 28.04 157
Tabular 136 24.29 293
Text 143 25.54 436
Time Series 124 22.14 560
Moda: Image 157 NA NA
# 1. Distribución de Algoritmos
freq_algorithm <- as.data.frame(table(datos$Algorithm))
freq_algorithm$Percentage <- round((freq_algorithm$Freq / sum(freq_algorithm$Freq)) * 100, 1)
# Ordenar los datos por la frecuencia de forma ascendente
freq_algorithm <- freq_algorithm[order(freq_algorithm$Freq), ]

ggplot(freq_algorithm, aes(x = reorder(Var1, Freq), y = Freq)) +  # Reorder para el orden ascendente
  geom_bar(stat = "identity", fill = "steelblue", color = "grey50") +  # Color gris para el contorno
  geom_text(aes(label = paste(Freq, "(", Percentage, "%)", sep="")), 
            vjust = -0.5, 
            size = 6, 
            angle = 0) +
  labs(title = "Distribución de Algoritmos", 
       x = "Algoritmo", 
       y = "Frecuencias (Porcentajes)") +
  theme_minimal(base_size = 18) + 
  theme(panel.grid.major = element_line(color = "grey90"),  # Añadir el grid
        panel.grid.minor = element_line(color = "grey90"),  # Añadir el grid menor
        panel.border = element_rect(color = "grey50", fill = NA),  # Añadir el borde
        plot.title = element_text(hjust = 0.5), 
        axis.text.x = element_text(angle = 45, hjust = 1)) +
  ylim(0, max(freq_algorithm$Freq) + 20)

# 2. Distribución de Frameworks
freq_framework <- as.data.frame(table(datos$Framework))
freq_framework$Percentage <- round((freq_framework$Freq / sum(freq_framework$Freq)) * 100, 1)
# Ordenar los datos por la frecuencia de forma ascendente
freq_framework <- freq_framework[order(freq_framework$Freq), ]

ggplot(freq_framework, aes(x = reorder(Var1, Freq), y = Freq)) +
  geom_bar(stat = "identity", fill = "lightgreen", color = "grey50") +  
  geom_text(aes(label = paste(Freq, "(", Percentage, "%)", sep="")), 
            vjust = -0.5, 
            size = 6, 
            angle = 0) +
  labs(title = "Distribución de Frameworks", 
       x = "Framework", 
       y = "Frecuencias (Porcentajes)") +
  theme_minimal(base_size = 18) + 
  theme(panel.grid.major = element_line(color = "grey90"),  
        panel.grid.minor = element_line(color = "grey90"),  
        panel.border = element_rect(color = "grey50", fill = NA),  
        plot.title = element_text(hjust = 0.5), 
        axis.text.x = element_text(angle = 45, hjust = 1)) +
  ylim(0, max(freq_framework$Freq) + 20)

# 3. Distribución de Tipos de Problema
freq_problem_type <- as.data.frame(table(datos$Problem_Type))
freq_problem_type$Percentage <- round((freq_problem_type$Freq / sum(freq_problem_type$Freq)) * 100, 1)
# Ordenar los datos por la frecuencia de forma ascendente
freq_problem_type <- freq_problem_type[order(freq_problem_type$Freq), ]

ggplot(freq_problem_type, aes(x = reorder(Var1, Freq), y = Freq)) +
  geom_bar(stat = "identity", fill = "lightcoral", color = "grey50") +  
  geom_text(aes(label = paste(Freq, "(", Percentage, "%)", sep="")), 
            vjust = -0.5, 
            size = 6, 
            angle = 0) +
  labs(title = "Distribución de Tipos de Problema", 
       x = "Tipo de Problema", 
       y = "Frecuencias (Porcentajes)") +
  theme_minimal(base_size = 18) + 
  theme(panel.grid.major = element_line(color = "grey90"),  
        panel.grid.minor = element_line(color = "grey90"),  
        panel.border = element_rect(color = "grey50", fill = NA),  
        plot.title = element_text(hjust = 0.5), 
        axis.text.x = element_text(angle = 45, hjust = 1)) +
  ylim(0, max(freq_problem_type$Freq) + 20)

# 4. Distribución de Tipos de Dataset
freq_dataset_type <- as.data.frame(table(datos$Dataset_Type))
freq_dataset_type$Percentage <- round((freq_dataset_type$Freq / sum(freq_dataset_type$Freq)) * 100, 1)
# Ordenar los datos por la frecuencia de forma ascendente
freq_dataset_type <- freq_dataset_type[order(freq_dataset_type$Freq), ]

ggplot(freq_dataset_type, aes(x = reorder(Var1, Freq), y = Freq)) +
  geom_bar(stat = "identity", fill = "lightgoldenrod", color = "grey50") +  
  geom_text(aes(label = paste(Freq, "(", Percentage, "%)", sep="")), 
            vjust = -0.5, 
            size = 6, 
            angle = 0) +
  labs(title = "Distribución de Tipos de Dataset", 
       x = "Tipo de Dataset", 
       y = "Frecuencias (Porcentajes)") +
  theme_minimal(base_size = 18) + 
  theme(panel.grid.major = element_line(color = "grey90"),  
        panel.grid.minor = element_line(color = "grey90"),  
        panel.border = element_rect(color = "grey50", fill = NA),  
        plot.title = element_text(hjust = 0.5), 
        axis.text.x = element_text(angle = 45, hjust = 1)) +
  ylim(0, max(freq_dataset_type$Freq) + 20)

# Calcular las proporciones de cada categoría en Problem_Type
prop_problem_type <- as.data.frame(table(datos$Problem_Type))
prop_problem_type$Percentage <- round((prop_problem_type$Freq / sum(prop_problem_type$Freq)) * 100, 1)

# Gráfico de torta (pie chart)
ggplot(prop_problem_type, aes(x = "", y = Freq, fill = Var1)) +
  geom_bar(width = 1, stat = "identity") +
  coord_polar(theta = "y") +  # Polar para hacer el gráfico de torta
  labs(title = "Distribución de Tipos de Problema",
       x = "",
       y = "") +
  theme_void() +  # Tema vacío para gráfico de torta
  theme(plot.title = element_text(hjust = 0.5, size = 20, face = "bold"),
        legend.title = element_text(size = 15),
        legend.text = element_text(size = 12)) +
  geom_text(aes(label = paste0(Percentage, "%")), 
            position = position_stack(vjust = 0.5), size = 5)

RESULTADOS EN TABLAS DE FRECUENCIA:

  • Algorithm: Podemos observar que K-Means es el algoritmo más común, mientras que Random Forest es el menos frecuente en los datos analizados. Los otros dos algoritmos, Neural Network y SVM, presentan frecuencias similares.
  • Framework: Se observa que TensorFlow es el framework preferido, con una diferencia significativa en relación con los demás. Por otro lado, Keras es el menos utilizado. Tanto PyTorch como Scikit-learn tienen frecuencias muy cercanas entre sí, lo que indica que son opciones igualmente populares.
  • Problem_Type: El análisis muestra que el Clustering es el tipo de problema más frecuente, seguido de cerca por la Regresión y la Clasificación. Aunque las diferencias en frecuencia no son drásticas, esta variabilidad sugiere que cada tipo de problema podría afectar de manera distinta el balance entre precisión y tiempo de entrenamiento.
  • Dataset_Type: En este análisis, el tipo de dataset más frecuente es Image, lo que lo convierte en la moda. Le sigue el tipo de dataset Text, luego Tabular. Finalmente, el tipo de dataset menos común es Time Series.

Variables Cuantitativas/Númericas

datos_numericos <- datos[, sapply(datos, is.numeric)]

summary(datos_numericos)
##     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    
##  Min.   : 0.1032  
##  1st Qu.: 1.2441  
##  Median : 2.4347  
##  Mean   : 2.9910  
##  3rd Qu.: 3.8131  
##  Max.   :46.9856  
##  NA's   :20

Tablas de frecuencias agrupadas

datos_filtrados <- datos$Accuracy[is.finite(datos$Accuracy) & !is.na(datos$Accuracy)] # Eliminar valores no finitos

# Definir los intervalos
intervalos <- cut(datos_filtrados, breaks = seq(min(datos_filtrados, na.rm = TRUE), 
                                                max(datos_filtrados, na.rm = TRUE), 
                                                length.out = 10), include.lowest = TRUE)

# Calcular las frecuencias absoluta, relativa y acumulada
frecuencia_absoluta <- table(intervalos)
frecuencia_relativa <- prop.table(frecuencia_absoluta)
frecuencia_acumulada <- cumsum(frecuencia_absoluta)
frecuencia_relativa_porcentaje <- frecuencia_relativa * 100
# Crear la tabla de frecuencias
tabla_frecuencias <- data.frame(
  Intervalo = names(frecuencia_absoluta),
  Frecuencia_Absoluta = as.numeric(frecuencia_absoluta),
  Frecuencia_Acumulada = as.numeric(frecuencia_acumulada),
  Frecuencia_Relativa = round(as.numeric(frecuencia_relativa_porcentaje), 2) # En porcentaje
)
# Fila al final con los totales
totales <- data.frame(
  Intervalo = "Total",
  Frecuencia_Absoluta = sum(tabla_frecuencias$Frecuencia_Absoluta),
  Frecuencia_Acumulada = NA, # No tiene sentido acumular en la fila total
  Frecuencia_Relativa = sum(tabla_frecuencias$Frecuencia_Relativa)
)
tabla_frecuencias <- rbind(tabla_frecuencias, totales)
# Mostrar la tabla usando kable
library(kableExtra)
tabla_frecuencias %>%
  kbl(caption = "Tabla de Frecuencias Agrupadas para la variable Accuracy", align = "c") %>%
  kable_styling(full_width = F, position = "center", font_size = 12) %>%
  row_spec(nrow(tabla_frecuencias), bold = TRUE, color = "white", background = "gray") 
Tabla de Frecuencias Agrupadas para la variable Accuracy
Intervalo Frecuencia_Absoluta Frecuencia_Acumulada Frecuencia_Relativa
[0.504,1.53] 511 511 98.08
(1.53,2.55] 0 511 0.00
(2.55,3.58] 0 511 0.00
(3.58,4.6] 0 511 0.00
(4.6,5.62] 2 513 0.38
(5.62,6.65] 2 515 0.38
(6.65,7.67] 1 516 0.19
(7.67,8.69] 3 519 0.58
(8.69,9.72] 2 521 0.38
Total 521 NA 99.99
datos_filtrados <- datos$Precision[is.finite(datos$Precision) & !is.na(datos$Precision)] 

intervalos <- cut(datos_filtrados, breaks = seq(min(datos_filtrados, na.rm = TRUE), 
                                                max(datos_filtrados, na.rm = TRUE), 
                                                length.out = 10), include.lowest = TRUE)

frecuencia_absoluta <- table(intervalos)
frecuencia_relativa <- prop.table(frecuencia_absoluta)
frecuencia_acumulada <- cumsum(frecuencia_absoluta)
frecuencia_relativa_porcentaje <- frecuencia_relativa * 100

tabla_frecuencias <- data.frame(
  Intervalo = names(frecuencia_absoluta),
  Frecuencia_Absoluta = as.numeric(frecuencia_absoluta),
  Frecuencia_Acumulada = as.numeric(frecuencia_acumulada),
  Frecuencia_Relativa = round(as.numeric(frecuencia_relativa_porcentaje), 2) 
)
totales <- data.frame(
  Intervalo = "Total",
  Frecuencia_Absoluta = sum(tabla_frecuencias$Frecuencia_Absoluta),
  Frecuencia_Acumulada = NA, # No tiene sentido acumular en la fila total
  Frecuencia_Relativa = sum(tabla_frecuencias$Frecuencia_Relativa)
)
tabla_frecuencias <- rbind(tabla_frecuencias, totales)
library(kableExtra)
tabla_frecuencias %>%
  kbl(caption = "Tabla de Frecuencias Agrupadas para la variable Precision", align = "c") %>%
  kable_styling(full_width = F, position = "center", font_size = 12) %>%
  row_spec(nrow(tabla_frecuencias), bold = TRUE, color = "white", background = "gray") 
Tabla de Frecuencias Agrupadas para la variable Precision
Intervalo Frecuencia_Absoluta Frecuencia_Acumulada Frecuencia_Relativa
[0.402,1.44] 531 531 98.15
(1.44,2.48] 0 531 0.00
(2.48,3.51] 0 531 0.00
(3.51,4.55] 3 534 0.55
(4.55,5.59] 1 535 0.18
(5.59,6.62] 2 537 0.37
(6.62,7.66] 1 538 0.18
(7.66,8.7] 0 538 0.00
(8.7,9.73] 3 541 0.55
Total 541 NA 99.98
datos_filtrados <- datos$Recall[is.finite(datos$Recall) & !is.na(datos$Recall)] 

intervalos <- cut(datos_filtrados, breaks = seq(min(datos_filtrados, na.rm = TRUE), 
                                                max(datos_filtrados, na.rm = TRUE), 
                                                length.out = 10), include.lowest = TRUE)

frecuencia_absoluta <- table(intervalos)
frecuencia_relativa <- prop.table(frecuencia_absoluta)
frecuencia_acumulada <- cumsum(frecuencia_absoluta)
frecuencia_relativa_porcentaje <- frecuencia_relativa * 100

tabla_frecuencias <- data.frame(
  Intervalo = names(frecuencia_absoluta),
  Frecuencia_Absoluta = as.numeric(frecuencia_absoluta),
  Frecuencia_Acumulada = as.numeric(frecuencia_acumulada),
  Frecuencia_Relativa = round(as.numeric(frecuencia_relativa_porcentaje), 2) 
)
totales <- data.frame(
  Intervalo = "Total",
  Frecuencia_Absoluta = sum(tabla_frecuencias$Frecuencia_Absoluta),
  Frecuencia_Acumulada = NA, # No tiene sentido acumular en la fila total
  Frecuencia_Relativa = sum(tabla_frecuencias$Frecuencia_Relativa)
)
tabla_frecuencias <- rbind(tabla_frecuencias, totales)
library(kableExtra)
tabla_frecuencias %>%
  kbl(caption = "Tabla de Frecuencias Agrupadas para la variable Recall", align = "c") %>%
  kable_styling(full_width = F, position = "center", font_size = 12) %>%
  row_spec(nrow(tabla_frecuencias), bold = TRUE, color = "white", background = "gray") 
Tabla de Frecuencias Agrupadas para la variable Recall
Intervalo Frecuencia_Absoluta Frecuencia_Acumulada Frecuencia_Relativa
[0.3,1.31] 530 530 98.15
(1.31,2.31] 0 530 0.00
(2.31,3.32] 0 530 0.00
(3.32,4.33] 1 531 0.19
(4.33,5.34] 2 533 0.37
(5.34,6.34] 4 537 0.74
(6.34,7.35] 0 537 0.00
(7.35,8.36] 2 539 0.37
(8.36,9.37] 1 540 0.19
Total 540 NA 100.01
datos_filtrados <- datos$F1_Score[is.finite(datos$F1_Score) & !is.na(datos$F1_Score)] 

intervalos <- cut(datos_filtrados, breaks = seq(min(datos_filtrados, na.rm = TRUE), 
                                                max(datos_filtrados, na.rm = TRUE), 
                                                length.out = 10), include.lowest = TRUE)

frecuencia_absoluta <- table(intervalos)
frecuencia_relativa <- prop.table(frecuencia_absoluta)
frecuencia_acumulada <- cumsum(frecuencia_absoluta)
frecuencia_relativa_porcentaje <- frecuencia_relativa * 100

tabla_frecuencias <- data.frame(
  Intervalo = names(frecuencia_absoluta),
  Frecuencia_Absoluta = as.numeric(frecuencia_absoluta),
  Frecuencia_Acumulada = as.numeric(frecuencia_acumulada),
  Frecuencia_Relativa = round(as.numeric(frecuencia_relativa_porcentaje), 2)
)
totales <- data.frame(
  Intervalo = "Total",
  Frecuencia_Absoluta = sum(tabla_frecuencias$Frecuencia_Absoluta),
  Frecuencia_Acumulada = NA, # No tiene sentido acumular en la fila total
  Frecuencia_Relativa = sum(tabla_frecuencias$Frecuencia_Relativa)
)
tabla_frecuencias <- rbind(tabla_frecuencias, totales)
library(kableExtra)
tabla_frecuencias %>%
  kbl(caption = "Tabla de Frecuencias Agrupadas para la variable F1_Score", align = "c") %>%
  kable_styling(full_width = F, position = "center", font_size = 12) %>%
  row_spec(nrow(tabla_frecuencias), bold = TRUE, color = "white", background = "gray") 
Tabla de Frecuencias Agrupadas para la variable F1_Score
Intervalo Frecuencia_Absoluta Frecuencia_Acumulada Frecuencia_Relativa
[0.4,1.4] 530 530 98.15
(1.4,2.39] 0 530 0.00
(2.39,3.39] 0 530 0.00
(3.39,4.39] 0 530 0.00
(4.39,5.39] 3 533 0.56
(5.39,6.38] 2 535 0.37
(6.38,7.38] 0 535 0.00
(7.38,8.38] 2 537 0.37
(8.38,9.37] 3 540 0.56
Total 540 NA 100.01
datos_filtrados <- datos$Training_Time[is.finite(datos$Training_Time) & !is.na(datos$Training_Time)] 

intervalos <- cut(datos_filtrados, breaks = seq(min(datos_filtrados, na.rm = TRUE), 
                                                max(datos_filtrados, na.rm = TRUE), 
                                                length.out = 10), include.lowest = TRUE)

frecuencia_absoluta <- table(intervalos)
frecuencia_relativa <- prop.table(frecuencia_absoluta)
frecuencia_acumulada <- cumsum(frecuencia_absoluta)
frecuencia_relativa_porcentaje <- frecuencia_relativa * 100

tabla_frecuencias <- data.frame(
  Intervalo = names(frecuencia_absoluta),
  Frecuencia_Absoluta = as.numeric(frecuencia_absoluta),
  Frecuencia_Acumulada = as.numeric(frecuencia_acumulada),
  Frecuencia_Relativa = round(as.numeric(frecuencia_relativa_porcentaje), 2) 
)
totales <- data.frame(
  Intervalo = "Total",
  Frecuencia_Absoluta = sum(tabla_frecuencias$Frecuencia_Absoluta),
  Frecuencia_Acumulada = NA, # No tiene sentido acumular en la fila total
  Frecuencia_Relativa = sum(tabla_frecuencias$Frecuencia_Relativa)
)
tabla_frecuencias <- rbind(tabla_frecuencias, totales)
library(kableExtra)
tabla_frecuencias %>%
  kbl(caption = "Tabla de Frecuencias Agrupadas para la variable Training_Time", align = "c") %>%
  kable_styling(full_width = F, position = "center", font_size = 12) %>%
  row_spec(nrow(tabla_frecuencias), bold = TRUE, color = "white", background = "gray") 
Tabla de Frecuencias Agrupadas para la variable Training_Time
Intervalo Frecuencia_Absoluta Frecuencia_Acumulada Frecuencia_Relativa
[0.103,5.31] 531 531 98.33
(5.31,10.5] 0 531 0.00
(10.5,15.7] 1 532 0.19
(15.7,20.9] 2 534 0.37
(20.9,26.1] 0 534 0.00
(26.1,31.4] 2 536 0.37
(31.4,36.6] 0 536 0.00
(36.6,41.8] 0 536 0.00
(41.8,47] 4 540 0.74
Total 540 NA 100.00

Medidas de Tendencia central

# Calcular media, moda y mediana para Accuracy
media_Accuracy <- mean(datos$Accuracy, na.rm = TRUE)
mediana_Accuracy <- median(datos$Accuracy, na.rm = TRUE)
moda <- function(x) {
  uniq <- unique(na.omit(x))
  uniq[which.max(tabulate(match(x, uniq)))]
}
moda_Accuracy <- moda(datos$Accuracy)
# Calcular media, moda y mediana para Precision
media_Precision <- mean(datos$Precision, na.rm = TRUE)
mediana_Precision <- median(datos$Precision, na.rm = TRUE)
moda_Precision <- moda(datos$Precision)
# Calcular media, moda y mediana para Recall
media_Recall <- mean(datos$Recall, na.rm = TRUE)
mediana_Recall <- median(datos$Recall, na.rm = TRUE)
moda_Recall <- moda(datos$Recall)
# Calcular media, moda y mediana para F1_Score 
media_F1_Score <- mean(datos$F1_Score, na.rm = TRUE)
mediana_F1_Score <- median(datos$F1_Score, na.rm = TRUE)
moda_F1_Score <- moda(datos$F1_Score)
# Calcular media, moda y mediana para Training_Time
media_Training_Time <- mean(datos$Training_Time, na.rm = TRUE)
mediana_Training_Time <- median(datos$Training_Time, na.rm = TRUE)
moda_Training_Time <- moda(datos$Training_Time)

# Crear un data frame con los resultados
resultados <- data.frame(
  Variable = c("Accuracy", "Precision", "Recall", "F1_Score", "Training_Time"),
  Media = c(media_Accuracy, media_Precision, media_Recall, media_F1_Score, media_Training_Time),
  Mediana = c(mediana_Accuracy, mediana_Precision, mediana_Recall, mediana_F1_Score, mediana_Training_Time),
  Moda = c(moda_Accuracy, moda_Precision, moda_Recall, moda_F1_Score, moda_Training_Time)
)
# Mostrar la tabla utilizando kableExtra
kable(resultados, col.names = c("Variable", "Media", "Mediana", "Moda")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = F) %>%
  row_spec(0, bold = TRUE, color = "white", background = "#4CAF50") %>%
  row_spec(1:3, background = "#f5f5f5")
Variable Media Mediana Moda
Accuracy 0.8778581 0.7578397 0.6618051
Precision 0.8129050 0.7194524 0.6929447
Recall 0.7485760 0.6492793 0.8766533
F1_Score 0.8121745 0.7086363 0.4426950
Training_Time 2.9910403 2.4347191 4.9785924

Medidas de dispersión

# Accuracy
rango_accuracy <- range(datos$Accuracy, na.rm = TRUE)
varianza_accuracy <- var(datos$Accuracy, na.rm = TRUE)
sd_accuracy <- sd(datos$Accuracy, na.rm = TRUE)
cv_accuracy <- sd_accuracy / mean(datos$Accuracy, na.rm = TRUE)
# Precision
rango_precision <- range(datos$Precision, na.rm = TRUE)
varianza_precision <- var(datos$Precision, na.rm = TRUE)
sd_precision <- sd(datos$Precision, na.rm = TRUE)
cv_precision <- sd_precision / mean(datos$Precision, na.rm = TRUE)
# Recall
rango_recall <- range(datos$Recall, na.rm = TRUE)
varianza_recall <- var(datos$Recall, na.rm = TRUE)
sd_recall <- sd(datos$Recall, na.rm = TRUE)
cv_recall <- sd_recall / mean(datos$Recall, na.rm = TRUE)
# F1_Score
rango_f1 <- range(datos$F1_Score, na.rm = TRUE)
varianza_f1 <- var(datos$F1_Score, na.rm = TRUE)
sd_f1 <- sd(datos$F1_Score, na.rm = TRUE)
cv_f1 <- sd_f1 / mean(datos$F1_Score, na.rm = TRUE)
# Training Time
rango_tt <- range(datos$Training_Time, na.rm = TRUE)
varianza_tt <- var(datos$Training_Time, na.rm = TRUE)
sd_tt <- sd(datos$Training_Time, na.rm = TRUE)
cv_tt <- sd_tt / mean(datos$Training_Time, na.rm = TRUE)

# Crear el dataframe con todas las medidas
tabla_dispersion <- data.frame(
  Variable = c("Accuracy", "Precision", "Recall", "F1_Score", "Training Time"),
  Rango = c(paste(rango_accuracy[1], "-", rango_accuracy[2]),
            paste(rango_precision[1], "-", rango_precision[2]),
            paste(rango_recall[1], "-", rango_recall[2]),
            paste(rango_f1[1], "-", rango_f1[2]),
            paste(rango_tt[1], "-", rango_tt[2])),
  Varianza = c(varianza_accuracy, varianza_precision, varianza_recall, varianza_f1, varianza_tt),
  `Desviación Estándar` = c(sd_accuracy, sd_precision, sd_recall, sd_f1, sd_tt),
  `Coeficiente de Variación` = c(cv_accuracy, cv_precision, cv_recall, cv_f1, cv_tt)
)

# Mostrar la tabla con kable
library(kableExtra)
tabla_dispersion %>%
  kbl(caption = "Medidas de Dispersión para Variables Cuantitativas", digits = 4, align = "c") %>%
  kable_styling(full_width = F, bootstrap_options = c("striped", "hover", "condensed"), 
                font_size = 12, position = "center") %>%
  column_spec(1, bold = TRUE, background = "lightblue")
Medidas de Dispersión para Variables Cuantitativas
Variable Rango Varianza Desviación.Estándar Coeficiente.de.Variación
Accuracy 0.50378143748907 - 9.718079600838 0.8895 0.9431 1.0743
Precision 0.40193095816257 - 9.7320081190236 0.7250 0.8515 1.0474
Recall 0.30009428510314 - 9.3661822765607 0.6153 0.7844 1.0479
F1_Score 0.40000698085322 - 9.3740486657127 0.7971 0.8928 1.0993
Training Time 0.10320161473037 - 46.985625752494 19.5704 4.4238 1.4790

Medidas de posición

# Calcular percentiles y cuartiles para cada variable
# Accuracy
percentiles_accuracy <- quantile(datos$Accuracy, probs = c(0.25, 0.5, 0.75), na.rm = TRUE)
# Precision
percentiles_precision <- quantile(datos$Precision, probs = c(0.25, 0.5, 0.75), na.rm = TRUE)
# Recall
percentiles_recall <- quantile(datos$Recall, probs = c(0.25, 0.5, 0.75), na.rm = TRUE)
# F1_Score
percentiles_f1 <- quantile(datos$F1_Score, probs = c(0.25, 0.5, 0.75), na.rm = TRUE)
# Training Time
percentiles_tt <- quantile(datos$Training_Time, probs = c(0.25, 0.5, 0.75), na.rm = TRUE)

# Crear el dataframe con los percentiles (Cuartiles)
tabla_posicion <- data.frame(
  Variable = c("Accuracy", "Precision", "Recall", "F1_Score", "Training Time"),
  Q1_25 = c(percentiles_accuracy[1], percentiles_precision[1], percentiles_recall[1], percentiles_f1[1], percentiles_tt[1]),
  Q2_50 = c(percentiles_accuracy[2], percentiles_precision[2], percentiles_recall[2], percentiles_f1[2], percentiles_tt[2]), # Mediana
  Q3_75 = c(percentiles_accuracy[3], percentiles_precision[3], percentiles_recall[3], percentiles_f1[3], percentiles_tt[3])
)

# Mostrar la tabla con kable
library(kableExtra)
tabla_posicion %>%
  kbl(caption = "Medidas de Posición: Percentiles y Cuartiles", digits = 4, align = "c") %>%
  kable_styling(full_width = F, bootstrap_options = c("striped", "hover", "condensed"), 
                font_size = 12, position = "center") %>%
  column_spec(1, bold = TRUE, background = "lightblue")
Medidas de Posición: Percentiles y Cuartiles
Variable Q1_25 Q2_50 Q3_75
Accuracy 0.6236 0.7578 0.8824
Precision 0.5632 0.7195 0.8596
Recall 0.4819 0.6493 0.8404
F1_Score 0.5515 0.7086 0.8438
Training Time 1.2441 2.4347 3.8131

Medidas de distribución

# Calcular la asimetría y la curtosis para cada variable
asimetria_accuracy <- skewness(datos$Accuracy, na.rm = TRUE)
curtosis_accuracy <- kurtosis(datos$Accuracy, na.rm = TRUE)

asimetria_precision <- skewness(datos$Precision, na.rm = TRUE)
curtosis_precision <- kurtosis(datos$Precision, na.rm = TRUE)

asimetria_recall <- skewness(datos$Recall, na.rm = TRUE)
curtosis_recall <- kurtosis(datos$Recall, na.rm = TRUE)

asimetria_f1 <- skewness(datos$F1_Score, na.rm = TRUE)
curtosis_f1 <- kurtosis(datos$F1_Score, na.rm = TRUE)

asimetria_tt <- skewness(datos$Training_Time, na.rm = TRUE)
curtosis_tt <- kurtosis(datos$Training_Time, na.rm = TRUE)

tabla_forma_distribucion <- data.frame(
  Variable = c("Accuracy", "Precision", "Recall", "F1_Score", "Training Time"),
  Asimetría = c(asimetria_accuracy, asimetria_precision, asimetria_recall, asimetria_f1, asimetria_tt),
  Curtosis = c(curtosis_accuracy, curtosis_precision, curtosis_recall, curtosis_f1, curtosis_tt)
)
library(kableExtra)
tabla_forma_distribucion %>%
  kbl(caption = "Medidas de Forma de Distribución: Asimetría y Curtosis", digits = 4, align = "c") %>%
  kable_styling(full_width = F, bootstrap_options = c("striped", "hover", "condensed"), 
                font_size = 12, position = "center") %>%
  column_spec(1, bold = TRUE, background = "lightblue")
Medidas de Forma de Distribución: Asimetría y Curtosis
Variable Asimetría Curtosis
Accuracy 7.3592 56.1738
Precision 8.0077 70.3743
Recall 7.3134 60.4005
F1_Score 7.5107 59.9427
Training Time 7.6694 67.7217

Podemos observar como la asimetría para todas las variables cuantitativas es positiva, lo que nos permite inducir que la distribución tiene una cola más larga hacia la derecha (asimetría a la derecha). En cuanto a la curtosis, siendo esta el “peso” de las colas de la distribución en comparación con una distribución normal, vemos como todo los resultados arrojados son mayor que 0, por lo que se dice que la distribución tiene curtosis de tipo leptocúrtica, esto significa que la distribución tiene colas más pesadas y es más puntiaguda en comparación con la distribución normal.

Pruebas de normalidad

Para el análisis de las variables cuantitativas, primero se utilizará la Prueba de Shapiro-Wilk con el objetivo de evaluar si los datos de cada variable siguen una distribución normal.

# Realizar las pruebas de Shapiro-Wilk para cada variable
resultados_shapiro <- data.frame(
  Variable = c("Accuracy", "Precision", "Recall", "F1_Score", "Training_Time"),
  W_Statistic = c(shapiro.test(datos$Accuracy)$statistic,
                  shapiro.test(datos$Precision)$statistic,
                  shapiro.test(datos$Recall)$statistic,
                  shapiro.test(datos$F1_Score)$statistic,
                  shapiro.test(datos$Training_Time)$statistic),
  p_value = c(shapiro.test(datos$Accuracy)$p.value,
              shapiro.test(datos$Precision)$p.value,
              shapiro.test(datos$Recall)$p.value,
              shapiro.test(datos$F1_Score)$p.value,
              shapiro.test(datos$Training_Time)$p.value),
  Conclusion = ifelse(c(shapiro.test(datos$Accuracy)$p.value,
                        shapiro.test(datos$Precision)$p.value,
                        shapiro.test(datos$Recall)$p.value,
                        shapiro.test(datos$F1_Score)$p.value,
                        shapiro.test(datos$Training_Time)$p.value) < 0.05,
                      "No normal", "Normal")
)

library(kableExtra)
resultados_shapiro %>%
  kbl(caption = "Resultados de la Prueba de Shapiro-Wilk", digits = 4, align = "c") %>%
  kable_styling(full_width = F, bootstrap_options = c("striped", "hover", "condensed"), 
                font_size = 12, position = "center") %>%
  column_spec(1, bold = TRUE, background = "lightblue")
Resultados de la Prueba de Shapiro-Wilk
Variable W_Statistic p_value Conclusion
Accuracy 0.2277 0 No normal
Precision 0.2564 0 No normal
Recall 0.3181 0 No normal
F1_Score 0.2547 0 No normal
Training_Time 0.3492 0 No normal

Implicaciones: -Rechazo de la Normalidad. La prueba de Shapiro-Wilk arroja un valor P igual a 0 (menor a 0.05 - valor de referencia), lo que sugiere que las diferencias entre los datos y una distribución normal son tan grandes que la probabilidad de que los datos sean normales es extremadamente baja.

Análisis de la distribución normal a través de pruebas gráficas:

HISTOGRAMAS:

# Histograma con curva de densidad para cada variable
# Accuracy
ggplot(datos, aes(x = Accuracy)) +
  geom_histogram(aes(y = ..density..), binwidth = 0.05, fill = "skyblue", color = "black") +
  geom_density(color = "red", size = 1.2) +
  labs(title = "Distribución de Accuracy con Curva de Densidad", x = "Accuracy", y = "Densidad") +
  theme_minimal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: The dot-dot notation (`..density..`) was deprecated in ggplot2 3.4.0.
## ℹ Please use `after_stat(density)` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: Removed 39 rows containing non-finite outside the scale range
## (`stat_bin()`).
## Warning: Removed 39 rows containing non-finite outside the scale range
## (`stat_density()`).

# Precision
ggplot(datos, aes(x = Precision)) +
  geom_histogram(aes(y = ..density..), binwidth = 0.05, fill = "lightgreen", color = "black") +
  geom_density(color = "red", size = 1.2) +
  labs(title = "Distribución de Precision con Curva de Densidad", x = "Precision", y = "Densidad") +
  theme_minimal()
## Warning: Removed 19 rows containing non-finite outside the scale range
## (`stat_bin()`).
## Warning: Removed 19 rows containing non-finite outside the scale range
## (`stat_density()`).

# Recall
ggplot(datos, aes(x = Recall)) +
  geom_histogram(aes(y = ..density..), binwidth = 0.05, fill = "lightcoral", color = "black") +
  geom_density(color = "red", size = 1.2) +
  labs(title = "Distribución de Recall con Curva de Densidad", x = "Recall", y = "Densidad") +
  theme_minimal()
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_bin()`).
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_density()`).

# F1_Score
ggplot(datos, aes(x = F1_Score)) +
  geom_histogram(aes(y = ..density..), binwidth = 0.05, fill = "lightblue", color = "black") +
  geom_density(color = "red", size = 1.2) +
  labs(title = "Distribución de F1_Score con Curva de Densidad", x = "F1_Score", y = "Densidad") +
  theme_minimal()
## Warning: Removed 20 rows containing non-finite outside the scale range (`stat_bin()`).
## Removed 20 rows containing non-finite outside the scale range
## (`stat_density()`).

# Training Time
ggplot(datos, aes(x = Training_Time)) +
  geom_histogram(aes(y = ..density..), binwidth = 0.05, fill = "orange", color = "black") +
  geom_density(color = "red", size = 1.2) +
  labs(title = "Distribución de Training Time con Curva de Densidad", x = "Training Time", y = "Densidad") +
  theme_minimal()
## Warning: Removed 20 rows containing non-finite outside the scale range (`stat_bin()`).
## Removed 20 rows containing non-finite outside the scale range
## (`stat_density()`).

GRÁFICO DE CAJAS Y BIGOTES:

# Boxplot para cada variable

# Accuracy
ggplot(datos, aes(y = Accuracy)) +
  geom_boxplot(fill = "skyblue", color = "black") +
  labs(title = "Diagrama de Caja para Accuracy", y = "Accuracy") +
  theme_minimal()
## Warning: Removed 39 rows containing non-finite outside the scale range
## (`stat_boxplot()`).

# Precision
ggplot(datos, aes(y = Precision)) +
  geom_boxplot(fill = "lightgreen", color = "black") +
  labs(title = "Diagrama de Caja para Precision", y = "Precision") +
  theme_minimal()
## Warning: Removed 19 rows containing non-finite outside the scale range
## (`stat_boxplot()`).

# Recall
ggplot(datos, aes(y = Recall)) +
  geom_boxplot(fill = "lightcoral", color = "black") +
  labs(title = "Diagrama de Caja para Recall", y = "Recall") +
  theme_minimal()
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_boxplot()`).

# F1_Score
ggplot(datos, aes(y = F1_Score)) +
  geom_boxplot(fill = "lightblue", color = "black") +
  labs(title = "Diagrama de Caja para F1_Score", y = "F1_Score") +
  theme_minimal()
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_boxplot()`).

# Training Time
ggplot(datos, aes(y = Training_Time)) +
  geom_boxplot(fill = "orange", color = "black") +
  labs(title = "Diagrama de Caja para Training Time", y = "Training Time") +
  theme_minimal()
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_boxplot()`).

GRÁFICO Q-Q(QUANTILE-QUANTILE):

# Gráfico Q-Q para cada variable

# Accuracy
qqnorm(datos$Accuracy, main = "Gráfico Q-Q de Accuracy")
qqline(datos$Accuracy, col = "red")

# Precision
qqnorm(datos$Precision, main = "Gráfico Q-Q de Precision")
qqline(datos$Precision, col = "red")

# Recall
qqnorm(datos$Recall, main = "Gráfico Q-Q de Recall")
qqline(datos$Recall, col = "red")

# F1_Score
qqnorm(datos$F1_Score, main = "Gráfico Q-Q de F1_Score")
qqline(datos$F1_Score, col = "red")

# Training Time
qqnorm(datos$Training_Time, main = "Gráfico Q-Q de Training Time")
qqline(datos$Training_Time, col = "red")

Valores NA (Not Available) en la base de datos:

El primer paso es analizar la cantidad de valores NA presentes en la base de datos:

#Identificar cantidad de valores NA en la base de datos
total_na <- sum(is.na(datos))
cat("Cantidad total de valores NA en la base de datos:", total_na, "\n")
## Cantidad total de valores NA en la base de datos: 118
#Identificar la cantidad de valores NA por cada columna
na_por_columna <- colSums(is.na(datos))
cat("Cantidad de valores NA por columna:\n")
## Cantidad de valores NA por columna:
print(na_por_columna)
##     Algorithm     Framework  Problem_Type  Dataset_Type      Accuracy 
##             0             0             0             0            39 
##     Precision        Recall      F1_Score Training_Time          Date 
##            19            20            20            20             0
#Identificar columnas que contienen valores NA
columnas_con_na <- names(na_por_columna[na_por_columna > 0])
cat("Columnas que contienen valores NA:", paste(columnas_con_na, collapse = ", "), "\n")
## Columnas que contienen valores NA: Accuracy, Precision, Recall, F1_Score, Training_Time

Ahora, creamos un gráficoque nos permita visualizar los valores faltantes(NA):

numeric_vars <- datos[, sapply(datos, is.numeric)]
numeric_vars_na <- numeric_vars[, colSums(is.na(numeric_vars)) > 0]

# Gráfico de agregación de NA solo para variables numéricas con valores faltantes
aggr(numeric_vars_na, numbers = TRUE, col = c("navyblue", "red"), 
     cex.axis = 0.7, gap = 3, ylab = c("Proporción de valores faltantes", "Patrón de faltantes"))

numeric_vars <- datos[, sapply(datos, is.numeric)]
md.pattern(numeric_vars)

##     Precision Recall F1_Score Training_Time Accuracy    
## 448         1      1        1             1        1   0
## 39          1      1        1             1        0   1
## 16          1      1        1             0        1   1
## 17          1      1        0             1        1   1
## 2           1      1        0             0        1   2
## 18          1      0        1             1        1   1
## 1           1      0        1             0        1   2
## 16          0      1        1             1        1   1
## 1           0      1        1             0        1   2
## 1           0      1        0             1        1   2
## 1           0      0        1             1        1   2
##            19     20       20            20       39 118
numeric_vars <- datos[, sapply(datos, is.numeric)]
gg_miss_var(numeric_vars, show_pct = TRUE)

library(Amelia)
missmap(datos_numericos, 
        main = "Mapa de Valores Faltantes", 
        col = c("black", "yellow"), 
        legend = TRUE)

Aplicación del método PMM para la imputación

El método PMM es ideal para variables numéricas, ya que utiliza valores observados similares a las predicciones del modelo para imputar los valores faltantes. Vamos a aplicar este método.

# Definir qué método usar para cada tipo de variable
metodos <- make.method(datos)

# Asignar 'pmm' a las variables numéricas que tienen NA
metodos[c("Accuracy", "Precision", "Recall", "F1_Score", "Training_Time")] <- "pmm"

# Verificar los métodos asignados
print(metodos)
##     Algorithm     Framework  Problem_Type  Dataset_Type      Accuracy 
##            ""            ""            ""            ""         "pmm" 
##     Precision        Recall      F1_Score Training_Time          Date 
##         "pmm"         "pmm"         "pmm"         "pmm"            ""
# Imputar usando PMM solo en variables numéricas
imp <- mice(datos, method = metodos, m = 5, maxit = 50, seed = 500)
## 
##  iter imp variable
##   1   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   1   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   1   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   1   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   1   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   2   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   2   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   2   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   2   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   2   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   3   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   3   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   3   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   3   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   3   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   4   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   4   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   4   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   4   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   4   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   5   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   5   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   5   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   5   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   5   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   6   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   6   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   6   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   6   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   6   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   7   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   7   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   7   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   7   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   7   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   8   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   8   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   8   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   8   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   8   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   9   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   9   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   9   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   9   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   9   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   10   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   10   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   10   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   10   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   10   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   11   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   11   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   11   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   11   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   11   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   12   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   12   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   12   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   12   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   12   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   13   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   13   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   13   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   13   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   13   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   14   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   14   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   14   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   14   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   14   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   15   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   15   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   15   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   15   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   15   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   16   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   16   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   16   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   16   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   16   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   17   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   17   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   17   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   17   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   17   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   18   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   18   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   18   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   18   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   18   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   19   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   19   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   19   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   19   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   19   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   20   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   20   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   20   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   20   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   20   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   21   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   21   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   21   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   21   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   21   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   22   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   22   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   22   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   22   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   22   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   23   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   23   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   23   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   23   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   23   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   24   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   24   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   24   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   24   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   24   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   25   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   25   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   25   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   25   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   25   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   26   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   26   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   26   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   26   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   26   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   27   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   27   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   27   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   27   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   27   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   28   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   28   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   28   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   28   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   28   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   29   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   29   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   29   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   29   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   29   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   30   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   30   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   30   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   30   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   30   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   31   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   31   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   31   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   31   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   31   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   32   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   32   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   32   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   32   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   32   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   33   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   33   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   33   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   33   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   33   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   34   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   34   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   34   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   34   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   34   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   35   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   35   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   35   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   35   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   35   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   36   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   36   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   36   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   36   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   36   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   37   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   37   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   37   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   37   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   37   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   38   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   38   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   38   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   38   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   38   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   39   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   39   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   39   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   39   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   39   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   40   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   40   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   40   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   40   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   40   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   41   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   41   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   41   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   41   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   41   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   42   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   42   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   42   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   42   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   42   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   43   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   43   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   43   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   43   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   43   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   44   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   44   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   44   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   44   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   44   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   45   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   45   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   45   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   45   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   45   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   46   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   46   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   46   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   46   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   46   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   47   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   47   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   47   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   47   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   47   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   48   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   48   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   48   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   48   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   48   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   49   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   49   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   49   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   49   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   49   5  Accuracy  Precision  Recall  F1_Score  Training_Time
##   50   1  Accuracy  Precision  Recall  F1_Score  Training_Time
##   50   2  Accuracy  Precision  Recall  F1_Score  Training_Time
##   50   3  Accuracy  Precision  Recall  F1_Score  Training_Time
##   50   4  Accuracy  Precision  Recall  F1_Score  Training_Time
##   50   5  Accuracy  Precision  Recall  F1_Score  Training_Time
## Warning: Number of logged events: 5
head(imp$imp) # Mostrar solo las primeras filas del resultado de la imputación
## $Algorithm
## [1] 1 2 3 4 5
## <0 rows> (o 0- extensión row.names)
## 
## $Framework
## [1] 1 2 3 4 5
## <0 rows> (o 0- extensión row.names)
## 
## $Problem_Type
## [1] 1 2 3 4 5
## <0 rows> (o 0- extensión row.names)
## 
## $Dataset_Type
## [1] 1 2 3 4 5
## <0 rows> (o 0- extensión row.names)
## 
## $Accuracy
##             1         2         3         4         5
## 9   0.5609430 0.6236155 0.6531268 0.7118691 0.8570435
## 16  0.7218751 0.6076009 0.9856975 0.7130907 0.7577980
## 30  0.9389872 0.5483382 0.9669375 0.5180802 0.6838797
## 34  0.9962418 0.9815576 0.6299066 0.5910590 0.8974048
## 45  0.8570435 9.4901527 0.6618051 0.9341363 0.9815576
## 107 0.5581832 0.7536174 0.5166016 0.7130417 0.7836561
## 116 0.7836561 0.9974332 0.6076009 0.5663579 0.7836561
## 130 0.8852037 0.5306748 0.5288903 0.9130338 0.6838797
## 138 0.8684369 0.7402535 0.9974332 0.7399694 0.6838797
## 144 0.5445622 0.7140998 0.7243468 0.5058103 0.5760124
## 146 0.7836561 0.6551810 0.8902628 0.9008640 0.8570435
## 148 0.6060224 0.9635173 0.5321045 0.7373154 0.7577980
## 159 0.7733487 0.9815576 5.9788899 0.7577980 0.7836561
## 163 0.7836561 0.5288903 0.7020702 0.8427826 0.7577980
## 164 0.6796167 0.7406721 0.8899255 0.9938928 0.7577980
## 181 0.5428291 0.5428291 0.5288903 0.8035470 0.6838797
## 187 0.5682199 0.7080770 0.6551810 0.5198094 0.7577980
## 189 0.7577980 0.6730499 0.9879369 0.5581832 0.9815576
## 194 0.5638567 0.7439270 0.6898929 0.7271887 0.5675831
## 221 0.8570435 0.5288903 0.5524651 0.7788917 0.8570435
## 224 0.5428291 0.9681061 0.8590615 0.9938928 0.8570435
## 239 0.7577980 0.8776352 0.6076009 0.7595299 0.7577980
## 245 0.9353767 0.8590615 0.8051669 0.7700060 0.7577980
## 281 0.9815576 0.8590615 5.9788899 0.8910140 0.7577980
## 285 0.6838797 0.6730499 0.9344525 0.6837672 0.7577980
## 288 0.7836561 0.5288903 0.6551810 0.5609430 0.9815576
## 302 0.9815576 0.9974332 0.5037814 0.8002972 0.6838797
## 316 0.8474755 0.9974332 0.6730499 0.9879369 0.9815576
## 335 0.9654743 0.7402535 0.6551810 0.6994114 0.7836561
## 339 0.7635207 0.9974332 0.6531268 0.7162489 0.7836561
## 367 0.6838797 0.6898929 0.6665010 0.7461389 0.8570435
## 384 0.9759059 0.7457973 0.7961752 0.7598870 0.9815576
## 415 0.7769011 0.7402535 0.8256165 0.6004668 0.6838797
## 423 0.9613786 0.9974332 0.6730499 0.7406721 0.6838797
## 427 0.6838797 0.7402535 0.5288903 0.5400574 0.6838797
## 441 0.9815576 0.5155670 0.7747648 0.7747648 0.7836561
## 471 0.9974332 0.9223916 0.7402535 0.7098637 0.7836561
## 534 0.7577980 0.9669375 0.7964754 0.5817619 0.7577980
## 550 0.9856975 0.5898416 0.6730499 0.7595409 0.7577980
## 
## $Precision
##             1         2         3         4         5
## 37  0.7330510 0.9134424 0.7140345 0.7330510 0.5560947
## 126 0.7075929 0.9113583 0.6506566 0.7558266 0.7050163
## 127 0.9802760 0.8975721 0.5505800 0.8593077 0.8297940
## 168 0.7050163 0.4648155 0.6506566 0.5689127 0.9149062
## 177 0.6582564 0.9909938 0.7702399 0.6625619 0.8367636
## 236 0.6926002 0.6098219 0.6171119 0.9341548 0.6506566
## 253 0.9399000 0.6749121 0.7050163 0.4531603 0.7808028
## 289 0.9149062 0.7432292 0.5505800 0.5124472 0.6506566
## 294 0.8261457 0.7925048 0.5505800 0.4648155 0.9048685
## 310 0.7050163 0.4201682 0.9048685 0.8721420 0.9048685
## 343 0.6641941 0.6621104 0.7050163 0.6625619 0.6132958
## 410 0.7936971 0.6466126 0.9149062 0.6367456 0.8297940
## 419 0.8821621 0.4790373 0.8297940 0.8213553 0.7702399
## 439 0.6506566 0.6812608 0.6171119 0.5528024 0.9048685
## 444 0.9513559 0.7558266 0.5505800 0.4710017 0.5505800
## 483 0.7558266 0.4406010 0.7050163 0.8424142 0.5505800
## 528 0.4493030 0.4688613 0.6171119 0.9990085 0.8297940
## 540 0.6749804 0.7787845 0.7050163 0.6466126 0.5833625
## 558 0.6366858 0.9273873 0.9048685 0.4953449 0.9149062
# Completar el dataset
datos_imputados <- complete(imp)

# Mostrar los primeros valores imputados
head(datos_imputados)
##        Algorithm    Framework Problem_Type Dataset_Type  Accuracy Precision
## 1            SVM Scikit-learn   Regression  Time Series 0.6618051 0.6929447
## 2        K-Means        Keras   Clustering  Time Series 0.7443216 0.4900292
## 3 Neural Network        Keras   Clustering        Image 0.8852037 0.5948056
## 4            SVM        Keras   Clustering         Text 0.8416477 0.8424142
## 5            SVM Scikit-learn   Regression      Tabular 0.7229514 0.6856109
## 6        K-Means      PyTorch   Regression        Image 0.6368133 0.6255330
##      Recall  F1_Score Training_Time                Date
## 1 0.9868006 0.4426950      4.978592 2023-03-08 11:26:21
## 2 0.8766533 0.4414046      3.721428 2023-03-09 11:26:21
## 3 0.9685424 0.9644707      3.282594 2023-03-10 11:26:21
## 4 0.8748388 0.7041523      4.041629 2023-03-11 11:26:21
## 5 0.3010956 0.6456472      3.603991 2023-03-12 11:26:21
## 6 7.4548096 0.8865271      3.006475 2023-03-13 11:26:21

Crear histogramas para comparar los datos originales e imputados

# Histogramas para Accuracy
ggp1 <- ggplot(data.frame(value = datos$Accuracy), aes(x = value)) +
  geom_histogram(fill = "#FBB000", color = "#F25221", alpha = 0.9, bins = 30) +
  ggtitle("Datos originales de Accuracy") +
  xlab("Accuracy") + ylab("Frecuencia") +
  theme_minimal()

ggp2 <- ggplot(data.frame(value = datos_imputados$Accuracy), aes(x = value)) +
  geom_histogram(fill = "#43B047", color = "#049CBB", alpha = 0.9, bins = 30) +
  ggtitle("Imputación con PMM (Accuracy)") +
  xlab("Accuracy") + ylab("Frecuencia") +
  theme_minimal()

# Mostrar los gráficos lado a lado
grid.arrange(ggp1, ggp2, ncol = 2)
## Warning: Removed 39 rows containing non-finite outside the scale range
## (`stat_bin()`).

# Histogramas para Precision
ggp3 <- ggplot(data.frame(value = datos$Precision), aes(x = value)) +
  geom_histogram(fill = "#FBB000", color = "#F25221", alpha = 0.9, bins = 30) +
  ggtitle("Datos originales de Precision") +
  xlab("Precision") + ylab("Frecuencia") +
  theme_minimal()

ggp4 <- ggplot(data.frame(value = datos_imputados$Precision), aes(x = value)) +
  geom_histogram(fill = "#43B047", color = "#049CBB", alpha = 0.9, bins = 30) +
  ggtitle("Imputación con PMM (Precision)") +
  xlab("Precision") + ylab("Frecuencia") +
  theme_minimal()

# Mostrar los gráficos lado a lado
grid.arrange(ggp3, ggp4, ncol = 2)
## Warning: Removed 19 rows containing non-finite outside the scale range
## (`stat_bin()`).

# Histogramas para Recall
ggp5 <- ggplot(data.frame(value = datos$Recall), aes(x = value)) +
  geom_histogram(fill = "#FBB000", color = "#F25221", alpha = 0.9, bins = 30) +
  ggtitle("Datos originales de Recall") +
  xlab("Recall") + ylab("Frecuencia") +
  theme_minimal()

ggp6 <- ggplot(data.frame(value = datos_imputados$Recall), aes(x = value)) +
  geom_histogram(fill = "#43B047", color = "#049CBB", alpha = 0.9, bins = 30) +
  ggtitle("Imputación con PMM (Recall)") +
  xlab("Recall") + ylab("Frecuencia") +
  theme_minimal()

# Mostrar los gráficos lado a lado
grid.arrange(ggp5, ggp6, ncol = 2)
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_bin()`).

# Histogramas para F1_Score
ggp7 <- ggplot(data.frame(value = datos$F1_Score), aes(x = value)) +
  geom_histogram(fill = "#FBB000", color = "#F25221", alpha = 0.9, bins = 30) +
  ggtitle("Datos originales de F1_Score") +
  xlab("F1_Score") + ylab("Frecuencia") +
  theme_minimal()

ggp8 <- ggplot(data.frame(value = datos_imputados$F1_Score), aes(x = value)) +
  geom_histogram(fill = "#43B047", color = "#049CBB", alpha = 0.9, bins = 30) +
  ggtitle("Imputación con PMM (F1_Score)") +
  xlab("F1_Score") + ylab("Frecuencia") +
  theme_minimal()

# Mostrar los gráficos lado a lado
grid.arrange(ggp7, ggp8, ncol = 2)
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_bin()`).

# Histogramas para Training_Time
ggp9 <- ggplot(data.frame(value = datos$Training_Time), aes(x = value)) +
  geom_histogram(fill = "#FBB000", color = "#F25221", alpha = 0.9, bins = 30) +
  ggtitle("Datos originales de Training_Time") +
  xlab("Training_Time") + ylab("Frecuencia") +
  theme_minimal()

ggp10 <- ggplot(data.frame(value = datos_imputados$Training_Time), aes(x = value)) +
  geom_histogram(fill = "#43B047", color = "#049CBB", alpha = 0.9, bins = 30) +
  ggtitle("Imputación con PMM (Training_Time)") +
  xlab("Training_Time") + ylab("Frecuencia") +
  theme_minimal()

# Mostrar los gráficos lado a lado
grid.arrange(ggp9, ggp10, ncol = 2)
## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_bin()`).

# Verificar si las imputaciones han sido completadas
colSums(is.na(datos_imputados))
##     Algorithm     Framework  Problem_Type  Dataset_Type      Accuracy 
##             0             0             0             0             0 
##     Precision        Recall      F1_Score Training_Time          Date 
##             0             0             0             0             0
# Gráfico de dispersión de Accuracy vs otras variables
xyplot(imp, Accuracy ~ Precision + Recall + F1_Score + Training_Time, 
       pch = 18, cex = 1, main = "Comparación de Accuracy con otras variables")

# Gráfico de dispersión de Precision vs otras variables
xyplot(imp, Precision ~ Accuracy + Recall + F1_Score + Training_Time, 
       pch = 18, cex = 1, main = "Comparación de Precision con otras variables")

# Gráfico de dispersión de Recall vs otras variables
xyplot(imp, Recall ~ Accuracy + Precision + F1_Score + Training_Time, 
       pch = 18, cex = 1, main = "Comparación de Recall con otras variables")

# Gráfico de dispersión de F1_Score vs otras variables
xyplot(imp, F1_Score ~ Accuracy + Precision + Recall + Training_Time, 
       pch = 18, cex = 1, main = "Comparación de F1_Score con otras variables")

# Gráfico de dispersión de Training_Time vs otras variables
xyplot(imp, Training_Time ~ Accuracy + Precision + Recall + F1_Score, 
       pch = 18, cex = 1, main = "Comparación de Training_Time con otras variables")

# Gráfico de densidad de los datos imputados vs observados
densityplot(imp, main = "Densidad de los Valores Imputados y Observados",
            col = c("blue", "red"))

# Gráfico de convergencia de las imputaciones
plot(imp)

Analisis de posibles valores atípicos:

Carcaterización:

#Función para contar valores atípicos
contar_atipicos <- 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
  atipicos <- x[x < lim_inferior | x > lim_superior]
  return(length(atipicos))
}

#Contar valores atípicos para cada variable numérica
num_Accuracy <- contar_atipicos(datos$Accuracy)
num_Precision <- contar_atipicos(datos$Precision)
num_Recall <- contar_atipicos(datos$Recall)
num_F1_Score <- contar_atipicos(datos$F1_Score)
num_Training_Time <- contar_atipicos(datos$Training_Time)

cat("Cantidad de valores atípicos en la variable Accuracy es:", num_Accuracy, "\n")
## Cantidad de valores atípicos en la variable Accuracy es: 49
cat("Cantidad de valores atípicos en la variable Precision es:", num_Precision, "\n")
## Cantidad de valores atípicos en la variable Precision es: 29
cat("Cantidad de valores atípicos en la variable Recall es:", num_Recall, "\n")
## Cantidad de valores atípicos en la variable Recall es: 30
cat("Cantidad de valores atípicos en la variable F1_Score es:", num_F1_Score, "\n")
## Cantidad de valores atípicos en la variable F1_Score es: 30
cat("Cantidad de valores atípicos en la variable Training_Time es:", num_Training_Time, "\n")
## Cantidad de valores atípicos en la variable Training_Time es: 29

A continuación se manejan los valores atípicos, y se visualizan las distribuciones de tres variables específicas(numéricas) a través de diagramas de caja (boxplots).

 par(mfrow=c(1,5))
 boxplot(datos$Accuracy,main="Accuracy")
 boxplot(datos$Precision,main="Precision")
 boxplot(datos$Recall,main="Recall")
 boxplot(datos$F1_Score,main="F1_Score")
 boxplot(datos$Training_Time,main="Training_Time")

De los gráficos anteriores podemos ver que: Las cuatro variables númericas presentan valores atípicos muy altos, por lo que se les dará su respectivo tratamiento.

Tratamiento de los valores atípicos

# Función para convertir valores atípicos a NA
convertir_atipicos_a_na <- 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
  # Reemplazar los valores atípicos por NA
  x <- ifelse(x < lim_inferior | x > lim_superior, NA, x)
  return(x)
}

# Aplicar la función a las variables numéricas
datos$Accuracy <- convertir_atipicos_a_na(datos$Accuracy)
datos$Precision <- convertir_atipicos_a_na(datos$Precision)
datos$Recall <- convertir_atipicos_a_na(datos$Recall)
datos$F1_Score <- convertir_atipicos_a_na(datos$F1_Score)
datos$Training_Time <- convertir_atipicos_a_na(datos$Training_Time)
# Función para imputar los NA con la mediana
imputar_na_con_mediana <- function(x) {
  x[is.na(x)] <- median(x, na.rm = TRUE)
  return(x)
}

# Aplicar la función a las variables numéricas
datos$Accuracy <- imputar_na_con_mediana(datos$Accuracy)
datos$Precision <- imputar_na_con_mediana(datos$Precision)
datos$Recall <- imputar_na_con_mediana(datos$Recall)
datos$F1_Score <- imputar_na_con_mediana(datos$F1_Score)
datos$Training_Time <- imputar_na_con_mediana(datos$Training_Time)

Ahora verificamos que efectivamente ya no quedan NA´s en la base de datos y la imputación fue exitosa.

# Verificar mediante boxplots después de la imputación
par(mfrow = c(1, 5))
boxplot(datos$Accuracy, main = "Accuracy (Imputado)")
boxplot(datos$Precision, main = "Precision (Imputado)")
boxplot(datos$Recall, main = "Recall (Imputado)")
boxplot(datos$F1_Score, main = "F1_Score (Imputado)")
boxplot(datos$Training_Time, main = "Training_Time (Imputado)")

datos_numericos <- datos[, sapply(datos, is.numeric)]
missmap(datos_numericos,
        main = "Mapa de Valores Faltantes",
        col = c("black", "yellow"),
        legend = TRUE)

##Análisis descriptivo de las variable

Análisis de variables categóricas

Vamos a generar tablas de contingencia para explorar las relaciones entre dos pares de variables categóricas:
- Algorithm y Framework
- Problem_Type y Dataset_Type

# Tabla de contingencia entre Algorithm y Framework
tabla_algo_framework <- table(datos$Algorithm, datos$Framework)

tabla_algo_framework %>%
  kbl(caption = "Tabla de Contingencia: Algorithm vs Framework") %>%
  kable_styling(full_width = F, bootstrap_options = c("striped", "hover", "condensed"))
Tabla de Contingencia: Algorithm vs Framework
Keras PyTorch Scikit-learn TensorFlow
K-Means 43 33 41 46
Neural Network 32 33 28 42
Random Forest 25 32 31 38
SVM 24 37 34 41
ggplot(as.data.frame(tabla_algo_framework), aes(Var1, Freq, fill = Var2)) +
  geom_bar(stat = "identity", position = "fill") +  
  scale_fill_brewer(palette = "Set2") + 
  labs(title = "Relación entre Algorithm y Framework", 
       x = "Algoritmo", 
       y = "Proporción dentro del Framework",
       fill = "Framework") +
  theme_minimal(base_size = 16) +
  theme(plot.title = element_text(hjust = 0.5), 
        axis.text.x = element_text(angle = 45, hjust = 1))

# Tabla de contingencia entre Problem_Type y Dataset_Type
tabla_problem_dataset <- table(datos$Problem_Type, datos$Dataset_Type)

tabla_problem_dataset %>%
  kbl(caption = "Tabla de Contingencia: Problem_Type vs Dataset_Type") %>%
  kable_styling(full_width = F, bootstrap_options = c("striped", "hover", "condensed"))
Tabla de Contingencia: Problem_Type vs Dataset_Type
Image Tabular Text Time Series
Classification 56 33 44 42
Clustering 54 52 47 43
Regression 47 51 52 39
ggplot(as.data.frame(tabla_problem_dataset), aes(Var1, Freq, fill = Var2)) +
  geom_bar(stat = "identity", position = "fill") +  
  scale_fill_brewer(palette = "Set3") +  
  labs(title = "Relación entre Problem_Type y Dataset_Type", 
       x = "Tipo de Problema", 
       y = "Proporción dentro del Tipo de Dataset",
       fill = "Tipo de Dataset") +
  theme_minimal(base_size = 16) +
  theme(plot.title = element_text(hjust = 0.5), 
        axis.text.x = element_text(angle = 45, hjust = 1))

Ahora se realizarán proporciones y análisis cruzado:

# Proporciones por filas
prop_filas_algo_framework <- prop.table(tabla_algo_framework, 1) * 100

# Mostrar la tabla con formato
prop_filas_algo_framework %>%
  kbl(digits = 2, caption = "Tabla 3: Proporciones por Filas entre Algoritmo y Framework (%)") %>%
  kable_styling(full_width = F, bootstrap_options = c("striped", "hover", "condensed"))
Tabla 3: Proporciones por Filas entre Algoritmo y Framework (%)
Keras PyTorch Scikit-learn TensorFlow
K-Means 26.38 20.25 25.15 28.22
Neural Network 23.70 24.44 20.74 31.11
Random Forest 19.84 25.40 24.60 30.16
SVM 17.65 27.21 25.00 30.15
# Convertir la tabla de proporciones en un dataframe
prop_algo_framework_df <- as.data.frame(as.table(prop_filas_algo_framework))

# Gráfico de heatmap
ggplot(prop_algo_framework_df, aes(Var2, Var1, fill = Freq)) +
  geom_tile(color = "white") +
  scale_fill_gradient(low = "white", high = "steelblue") +
  labs(title = "Heatmap de Proporciones entre Algoritmo y Framework",
       x = "Framework",
       y = "Algoritmo",
       fill = "Proporción (%)") +
  theme_minimal(base_size = 15) +
  theme(plot.title = element_text(hjust = 0.5, size = 15, face = "bold", margin = margin(b = 20)),  
        axis.title.x = element_text(size = 15, margin = margin(t = 10)),  
        axis.title.y = element_text(size = 15, margin = margin(r = 10)),  
        axis.text.x = element_text(size = 12),  
        axis.text.y = element_text(size = 12),  
        legend.title = element_text(size = 15),  
        legend.text = element_text(size = 12))  

# Proporciones por columnas
prop_columnas_problem_dataset <- prop.table(tabla_problem_dataset, 2) * 100

# Mostrar la tabla con formato
prop_columnas_problem_dataset %>%
  kbl(digits = 2, caption = "Tabla 4: Proporciones por Columnas entre Tipo de Problema y Tipo de Dataset (%)") %>%
  kable_styling(full_width = F, bootstrap_options = c("striped", "hover", "condensed"))
Tabla 4: Proporciones por Columnas entre Tipo de Problema y Tipo de Dataset (%)
Image Tabular Text Time Series
Classification 35.67 24.26 30.77 33.87
Clustering 34.39 38.24 32.87 34.68
Regression 29.94 37.50 36.36 31.45
# Convertir la tabla de proporciones en un dataframe
prop_problem_dataset_df <- as.data.frame(as.table(prop_columnas_problem_dataset))

# Gráfico de heatmap mejorado para Problem_Type vs Dataset_Type
ggplot(prop_problem_dataset_df, aes(Var2, Var1, fill = Freq)) +
  geom_tile(color = "white") +
  scale_fill_gradient(low = "white", high = "lightcoral") +
  labs(title = "Heatmap de Proporciones entre Tipo de Problema y Tipo de Dataset",
       x = "Tipo de Dataset",
       y = "Tipo de Problema",
       fill = "Proporción (%)") +
  theme_minimal(base_size = 15) +
  theme(plot.title = element_text(hjust = 0.5, size = 12, face = "bold", margin = margin(b = 20)),  
        axis.title.x = element_text(size = 15, margin = margin(t = 10)), 
        axis.title.y = element_text(size = 15, margin = margin(r = 10)),  
        axis.text.x = element_text(size = 12),  
        axis.text.y = element_text(size = 12),  
        legend.title = element_text(size = 15),  
        legend.text = element_text(size = 12))  

  1. Interpretación de la Relación entre Algorithm y Framework La tabla de contingencia y el heatmap muestran cómo se distribuyen los algoritmos en los distintos frameworks. Observamos que:
  • K-Means se utiliza predominantemente en Scikit-learn, lo cual es coherente dado que Scikit-learn es ampliamente utilizado para algoritmos de aprendizaje automático tradicionales.
  • Neural Network tiene una mayor presencia en TensorFlow y PyTorch, frameworks diseñados para modelos de redes neuronales y aprendizaje profundo.
  • Random Forest se implementa principalmente en Scikit-learn, ya que este framework ofrece una implementación robusta para este algoritmo.
  • SVM también es común en Scikit-learn, reflejando su fuerte soporte para algoritmos de clasificación. Esta distribución sugiere que la elección del framework está influenciada por el tipo de algoritmo y sus requisitos específicos.
  1. Interpretación de la Relación entre Problem_Type y Dataset_Type Al analizar la tabla de contingencia y el heatmap, notamos que:
  • Clasificación se aplica frecuentemente en datasets de tipo Image y Text, lo cual es lógico, ya que muchas tareas de clasificación involucran reconocimiento de imágenes y análisis de texto.
  • Regresión está más asociada con datasets Tabular y de Time Series, ya que estos tipos de datos son comunes en problemas de predicción de valores continuos.
  • Clustering muestra una distribución más equilibrada, pero tiene una ligera preferencia por datasets Tabular y Image.

Análisis de variables númericas

Análisis de correlaciones:

# Gráfico de dispersión entre Precision y Recall
ggplot(datos, aes(x = Precision, y = Recall)) +
  geom_point(color = "steelblue", size = 3, alpha = 0.6) +
  labs(title = "Relación entre Precisión y Recall",
       x = "Precisión",
       y = "Recall") +
  theme_minimal(base_size = 15)

# Calcular la matriz de correlación
cor_matrix <- cor(datos[, c("Accuracy", "Precision", "Recall", "Training_Time")], use = "complete.obs")

# Mostrar la matriz de correlación
print(cor_matrix)
##                  Accuracy   Precision      Recall Training_Time
## Accuracy       1.00000000 -0.10075707  0.02555252   -0.03910346
## Precision     -0.10075707  1.00000000 -0.01814039    0.03632114
## Recall         0.02555252 -0.01814039  1.00000000   -0.06268609
## Training_Time -0.03910346  0.03632114 -0.06268609    1.00000000
# Transformar la matriz de correlación en un formato largo para ggplot
cor_melted <- melt(cor_matrix)

# Gráfico de correlación (heatmap)
ggplot(cor_melted, aes(x = Var1, y = Var2, fill = value)) +
  geom_tile() +
  scale_fill_gradient2(low = "red", high = "blue", mid = "white", midpoint = 0, limit = c(-1,1)) +
  labs(title = "Matriz de Correlación",
       x = "",
       y = "") +
  theme_minimal(base_size = 15) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Podemos observar que los valores de correlación son muy pequeños entre dos variables diferentes, lo que indica que las variables no están fuertemente correlacionadas entre sí. Esto nos permite inducir que las variables no tienen una relación lineal significativa.

Interpretación: - Valores cercanos a 1 o -1 indican una fuerte correlación positiva o negativa, respectivamente. - Valores cercanos a 0 (caso arrojado) indican una correlación débil o inexistente. En este caso, los valores de correlación están bastante cerca de 0, lo que indica que las variables cuantitativas (Accuracy, Precision, Recall, Training_Time) no están linealmente relacionadas de manera fuerte.

NOTA: Es importante destacar que el resto de las pruebas y procedimientos relacionados con el análisis de datos, tales como la identificación de valores atípicos, el resumen estadístico de las variables y las pruebas de normalidad ya fueron abordados previamente en el desarrollo del EDA.

Análisis Bivariado

Este análisis estará guiado a dar respuesta a la pregunta problema planteada al inicio. Dado que las variables numéricas (como el tiempo de entrenamiento y la precisión) no están normalmente distribuidas y estás relacionando variables categóricas (como el tipo de problema, algoritmo y framework), la prueba adecuada sería una prueba no paramétrica, ya que no se hacen suposiciones sobre la distribución normal de los datos.

En este caso, las pruebas adecuadas serían:

  1. Prueba de U de Mann-Whitney:
# Filtrar los datos para Random Forest y Scikit-learn
datos_filtrados <- subset(datos, Algorithm == "Random Forest" & Framework == "Scikit-learn")

# Clasificación vs Regresión
subset_1 <- subset(datos_filtrados, Problem_Type %in% c("Classification", "Regression"))
mann_whitney_test_1 <- wilcox.test(Training_Time ~ Problem_Type, data = subset_1)

# Clasificación vs Clustering
subset_2 <- subset(datos_filtrados, Problem_Type %in% c("Classification", "Clustering"))
mann_whitney_test_2 <- wilcox.test(Training_Time ~ Problem_Type, data = subset_2)

# Regresión vs Clustering
subset_3 <- subset(datos_filtrados, Problem_Type %in% c("Regression", "Clustering"))
mann_whitney_test_3 <- wilcox.test(Training_Time ~ Problem_Type, data = subset_3)

# Mostrar los resultados
print(mann_whitney_test_1)
## 
##  Wilcoxon rank sum exact test
## 
## data:  Training_Time by Problem_Type
## W = 61, p-value = 0.896
## alternative hypothesis: true location shift is not equal to 0
print(mann_whitney_test_2)
## 
##  Wilcoxon rank sum exact test
## 
## data:  Training_Time by Problem_Type
## W = 63, p-value = 0.05031
## alternative hypothesis: true location shift is not equal to 0
print(mann_whitney_test_3)
## 
##  Wilcoxon rank sum exact test
## 
## data:  Training_Time by Problem_Type
## W = 36, p-value = 0.1444
## alternative hypothesis: true location shift is not equal to 0
  1. Clasificación vs Regresión: Interpretación: No hay diferencias significativas en el tiempo de entrenamiento entre los problemas de clasificación y regresión (p > 0.05).

  2. Clasificación vs Clustering: Interpretación: Este resultado es casi significativo, con un p-valor muy cercano a 0.05. Esto indica que podría haber una diferencia en el tiempo de entrenamiento entre los problemas de clasificación y clustering, pero no es lo suficientemente fuerte para ser concluyente.

  3. Regresión vs Clustering: Interpretación: No hay diferencias significativas en el tiempo de entrenamiento entre los problemas de regresión y clustering (p > 0.05).

  4. Prueba de Correlación de Spearman

# Filtrar los datos para Random Forest y Scikit-learn
datos_filtrados <- subset(datos, Algorithm == "Random Forest" & Framework == "Scikit-learn")

# Realizar la correlación de Spearman entre Training_Time y Precision
spearman_test <- cor.test(datos_filtrados$Training_Time, datos_filtrados$Precision, method = "spearman")

# Mostrar el resultado
print(spearman_test)
## 
##  Spearman's rank correlation rho
## 
## data:  datos_filtrados$Training_Time and datos_filtrados$Precision
## S = 4668, p-value = 0.7524
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##        rho 
## 0.05887097

Interpretación: - Coeficiente rho: Un valor de 0.0589 indica que la relación entre el tiempo de entrenamiento y la precisión es prácticamente inexistente (muy cercana a cero). - p-valor: El p-valor de 0.7524 es mayor que 0.05, lo que significa que no hay una correlación significativa entre el tiempo de entrenamiento y la precisión bajo Random Forest y Scikit-learn.

Componente gráfico y visualizaciones:

Gráfico de Comparación de Tiempos de Entrenamiento por Tipo de Problema

# Gráfico de boxplot para comparar el tiempo de entrenamiento entre los tipos de problemas
ggplot(datos_filtrados, aes(x = Problem_Type, y = Training_Time, fill = Problem_Type)) +
  geom_boxplot(outlier.colour = "white", outlier.size = 2) +
  labs(title = "Comparación de Tiempos de Entrenamiento por Tipo de Problema",
       x = "Tipo de Problema",
       y = "Tiempo de Entrenamiento (Horas)") +
  theme_minimal(base_size = 15) +
  theme(legend.position = "none")

El gráfico puede mostrar ciertas diferencias en la dispersión o rangos de los tiempos de entrenamiento entre los tipos de problemas, pero estas diferencias no son necesariamente significativas.

Gráfico de Dispersión de Training Time vs Precision

# Gráfico de dispersión para mostrar la relación entre tiempo de entrenamiento y precisión
ggplot(datos_filtrados, aes(x = Training_Time, y = Precision, color = Problem_Type)) +
  geom_point(size = 3) +
  geom_smooth(method = "lm", se = FALSE) +  # Añadir líneas de tendencia
  labs(title = "Relación entre Tiempo de Entrenamiento y Precisión",
       x = "Tiempo de Entrenamiento (Horas)",
       y = "Precisión") +
  theme_minimal(base_size = 15)
## `geom_smooth()` using formula = 'y ~ x'

Como se puede ver, los puntos están distribuidos de manera dispersa, lo que confirma los resultados de las pruebas estadísticas de Spearman, donde no se encontró una correlación significativa entre el tiempo de entrenamiento y la precisión.

Posible tendencia visual: Aunque los resultados estadísticos no muestran significancia, el gráfico podría sugerir, de manera visual, que los modelos de Clustering tienden a tener tiempos de entrenamiento más bajos con precisión más alta en general.

HALLAZGOS E INTERPRETACIONES

En este análisis exploratorio de datos, se buscó responder la pregunta clave: ¿Qué tipo de problema logra el menor tiempo de entrenamiento sin comprometer la precisión, utilizando el algoritmo Random Forest y el framework Scikit-learn?. Para abordar esta pregunta, se realizó una serie de análisis estadísticos y pruebas analíticas no paramétricas, dada la naturaleza de las variables en el conjunto de datos.

Los análisis realizados, incluidos la prueba U de Mann-Whitney y la correlación de Spearman, arrojaron resultados no concluyentes en cuanto a la relación entre el tipo de problema y las métricas de desempeño como el tiempo de entrenamiento y la precisión.

A pesar de la expectativa inicial de que ciertos tipos de problemas podrían diferir en su desempeño en términos de tiempo y precisión, los resultados indican que el tipo de problema no tiene un efecto significativo sobre el tiempo de entrenamiento ni sobre la precisión bajo Random Forest y Scikit-learn en este conjunto de datos.

Esto podría deberse a varias razones, entre esas la homogeneidad del dataset. El conjunto de datos utilizado podría no tener suficientes diferencias entre los tipos de problemas para que estas se manifiesten en el tiempo de entrenamiento o la precisión. Si los problemas fueran más diversos o si el tamaño de los datos fuera mayor, es posible que se observaran diferencias más marcadas.

Aunque no se observaron diferencias significativas entre los tiempos de entrenamiento ni la precisión de los modelos para los distintos tipos de problemas, los resultados muestran que el enfoque utilizado ofrece un rendimiento robusto y estable en general. Este análisis confirma que Random Forest, combinado con Scikit-learn, proporciona una opción confiable para abordar problemas de machine learning sin comprometer la precisión mientras se optimiza el tiempo de entrenamiento.