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.
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.
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:10,], caption= "Tabla 1: DataSet ") %>%
kable_styling(full_width = F) %>%
column_spec(2, width = "20em") %>%
scroll_box(width = "900px", height = "450px")
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.978592 | 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.282594 | 2023-03-10 11:26:21 |
SVM | Keras | Clustering | Text | 0.8416477 | 0.8424142 | 0.8748388 | 0.7041523 | 4.041629 | 2023-03-11 11:26:21 |
SVM | Scikit-learn | Regression | Tabular | 0.7229514 | 0.6856109 | 0.3010956 | 0.6456472 | 3.603991 | 2023-03-12 11:26:21 |
K-Means | PyTorch | Regression | Image | 0.6368133 | 0.6255330 | 7.4548096 | 0.8865271 | 3.006475 | 2023-03-13 11:26:21 |
Neural Network | PyTorch | Regression | Text | 0.9985622 | 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.328345 | 2023-03-15 11:26:21 |
SVM | Keras | Regression | Time Series | NA | 0.8710099 | 0.3416673 | 0.8161708 | 3.406453 | 2023-03-16 11:26:21 |
Random Forest | Keras | Regression | Text | 0.5818119 | 0.9352508 | NA | 0.8626737 | 3.419905 | 2023-03-17 11:26:21 |
dim(datos)
## [1] 560 10
El resultado muestra un data frame con 560 observaciones y 10 variables. Este tamaño de muestra es suficiente para realizar un análisis significativo, ya que permite identificar patrones y relaciones en los datos.
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"
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" ...
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 para las variables cualitativas
table(datos$Algorithm)
##
## K-Means Neural Network Random Forest SVM
## 163 135 126 136
counts <- table(datos$Algorithm)
bp <- barplot(counts,
main="Frecuencia de Algoritmos",
xlab="Algoritmo",
ylab="Frecuencia",
col="lightblue",
ylim=c(0, max(counts) + 10),
cex.main=1.5,
cex.lab=1.2,
cex.axis=1)
text(x=bp, y=counts + 6, labels=counts, cex=1, col="black")
Esta información permite 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.
table(datos$Framework)
##
## Keras PyTorch Scikit-learn TensorFlow
## 124 135 134 167
counts <- table(datos$Framework)
bp <- barplot(counts,
main="Frecuencia de Frameworks",
xlab="Framework",
ylab="Frecuencia",
col="lightgreen",
ylim=c(0, max(counts) + 10),
cex.main=1.5,
cex.lab=1.2,
cex.axis=1)
text(x=bp, y=counts+6, labels=counts, cex=1, col="black")
A partir de esto, 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.
table(datos$Problem_Type)
##
## Classification Clustering Regression
## 175 196 189
counts <- table(datos$Problem_Type)
bp <- barplot(counts,
main="Frecuencia de Tipos de Problema",
xlab="Tipo de Problema",
ylab="Frecuencia",
col="lightcoral",
ylim=c(0, max(counts) + 10),
cex.main=1.5,
cex.lab=1.2,
cex.axis=1)
text(x=bp, y=counts + 6, labels=counts, cex=1, col="black")
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.
table(datos$Dataset_Type)
##
## Image Tabular Text Time Series
## 157 136 143 124
counts <- table(datos$Dataset_Type)
bp <- barplot(counts,
main="Frecuencia de Tipos de Dataset",
xlab="Tipo de Dataset",
ylab="Frecuencia",
col="lightgoldenrod",
ylim=c(0, max(counts) + 15),
cex.main=1.5,
cex.lab=1.2,
cex.axis=1)
text(x=bp, y=counts+6, labels=counts, cex=1, col="black")
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.
# Resumen estadístico para las variables cuantitativas
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
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. Antes de proceder con la visualización gráfica, se realizará una limpieza de los datos, eliminando tanto los valores atípicos como los casos con valores faltantes, ya que estos pueden distorsionar la visualización. Después de depurar los datos de outliers y NAs, se procederá a graficar las distribuciones sin la interferencia de estos casos, permitiendo obtener una representación más clara y precisa de la distribución de los datos.
shapiro.test(datos$Accuracy)
##
## Shapiro-Wilk normality test
##
## data: datos$Accuracy
## W = 0.22771, p-value < 2.2e-16
shapiro.test(datos$Precision)
##
## Shapiro-Wilk normality test
##
## data: datos$Precision
## W = 0.25643, p-value < 2.2e-16
shapiro.test(datos$Recall)
##
## Shapiro-Wilk normality test
##
## data: datos$Recall
## W = 0.31806, p-value < 2.2e-16
shapiro.test(datos$F1_Score)
##
## Shapiro-Wilk normality test
##
## data: datos$F1_Score
## W = 0.2547, p-value < 2.2e-16
shapiro.test(datos$Training_Time)
##
## Shapiro-Wilk normality test
##
## data: datos$Training_Time
## W = 0.34923, p-value < 2.2e-16
Los resultados de las pruebas de normalidad de Shapiro-Wilk para las variables Accuracy, Precision, Recall, F1_Score, y Training_Time indican que ninguna de las variables sigue una distribución normal, ya que en todos los casos el p-valor fue significativamente menor a 0.05. Dado que los datos no son normales, el enfoque más adecuado sería imputar los valores faltantes usando la mediana.
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
## ##
missmap(datos,
main = "Mapa de Valores Faltantes",
col = c("black", "yellow"),
legend = TRUE)
# Imputar NAs con la mediana
datos$Accuracy[is.na(datos$Accuracy)] <- median(datos$Accuracy, na.rm = TRUE)
datos$Precision[is.na(datos$Precision)] <- median(datos$Precision, na.rm = TRUE)
datos$Recall[is.na(datos$Recall)] <- median(datos$Recall, na.rm = TRUE)
datos$F1_Score[is.na(datos$F1_Score)] <- median(datos$F1_Score, na.rm = TRUE)
datos$Training_Time[is.na(datos$Training_Time)] <- median(datos$Training_Time, na.rm = TRUE)
missmap(datos,
main = "Mapa de Valores Faltantes",
col = c("black", "yellow"),
legend = TRUE)
Ahora, procederemos a graficar las variables para detectar posibles valores atípicos, utilizaremos diagramas de caja y bigotes (boxplots).
# Boxplot para Accuracy
boxplot(datos$Accuracy,
main="Distribución de Accuracy",
ylab="Valores de Accuracy",
col="lightgoldenrod",
ylim=c(min(datos$Accuracy, na.rm = TRUE) - 1, max(datos$Accuracy, na.rm = TRUE) + 1),
cex.main=1.5,
cex.lab=1.2,
cex.axis=1,
outline=TRUE)
datos$Accuracy[datos$Accuracy > 4] <- median(datos$Accuracy, na.rm = TRUE)
# Boxplot para Accuracy sin los outliers con anotaciones
boxplot(datos$Accuracy,
main="Distribución de Accuracy (Sin Outliers)",
ylab="Valores de Accuracy",
col="lightgoldenrod",
ylim=c(min(datos$Accuracy, na.rm = TRUE) - 1, max(datos$Accuracy, na.rm = TRUE) + 1),
cex.main=1.5,
cex.lab=1.2,
cex.axis=1,
outline=TRUE)
# Boxplot para Precision
boxplot(datos$Precision,
main="Distribución de Precision",
ylab="Valores de Precision",
col="blue",
ylim=c(min(datos$Precision, na.rm = TRUE) - 1, max(datos$Precision, na.rm = TRUE) + 1),
cex.main=1.5,
cex.lab=1.2,
cex.axis=1,
outline=TRUE)
datos$Precision[datos$Precision > 2] <- median(datos$Precision, na.rm = TRUE)
# Boxplot para Precision sin los outliers con anotaciones
boxplot(datos$Precision,
main="Distribución de Precision (Sin Outliers)",
ylab="Valores de Precision",
col="blue",
ylim=c(min(datos$Precision, na.rm = TRUE) - 1, max(datos$Precision, na.rm = TRUE) + 1),
cex.main=1.5,
cex.lab=1.2,
cex.axis=1,
outline=TRUE)
# Boxplot para Recall
boxplot(datos$Recall,
main="Distribución de Recall",
ylab="Valores de Recall",
col="red",
ylim=c(min(datos$Recall, na.rm = TRUE) - 1, max(datos$Recall, na.rm = TRUE) + 1),
cex.main=1.5,
cex.lab=1.2,
cex.axis=1,
outline=TRUE)
datos$Recall[datos$Recall > 2] <- median(datos$Recall, na.rm = TRUE)
# Boxplot para Recall sin los outliers con anotaciones
boxplot(datos$Recall,
main="Distribución de Recall (Sin Outliers)",
ylab="Valores de Recall",
col="red",
ylim=c(min(datos$Recall, na.rm = TRUE) - 1, max(datos$Recall, na.rm = TRUE) + 1),
cex.main=1.5,
cex.lab=1.2,
cex.axis=1,
outline=TRUE)
# Boxplot para F1_Score
boxplot(datos$F1_Score,
main="Distribución de F1_Score",
ylab="Valores de F1_Score",
col="orange",
ylim=c(min(datos$F1_Score, na.rm = TRUE) - 1, max(datos$F1_Score, na.rm = TRUE) + 1),
cex.main=1.5,
cex.lab=1.2,
cex.axis=1,
outline=TRUE)
datos$F1_Score[datos$F1_Score > 4 ] <- median(datos$F1_Score, na.rm = TRUE)
# Boxplot para Recall sin los outliers con anotaciones
boxplot(datos$F1_Score,
main="Distribución de F1_Score (Sin Outliers)",
ylab="Valores de F1_Score",
col="orange",
ylim=c(min(datos$F1_Score, na.rm = TRUE) - 1, max(datos$F1_Score, na.rm = TRUE) + 1),
cex.main=1.5,
cex.lab=1.2,
cex.axis=1,
outline=TRUE)
# Boxplot para Training_Time
boxplot(datos$Training_Time,
main="Distribución de Training_Time",
ylab="Valores de Training_Time",
col="green",
ylim=c(min(datos$Training_Time, na.rm = TRUE) - 1, max(datos$Training_Time, na.rm = TRUE) + 1),
cex.main=1.5,
cex.lab=1.2,
cex.axis=1,
outline=TRUE)
datos$Training_Time[datos$Training_Time > 10 ] <- median(datos$Training_Time, na.rm = TRUE)
# Boxplot para Recall sin los outliers con anotaciones
boxplot(datos$Training_Time,
main="Distribución de Training_Time (Sin Outliers)",
ylab="Valores de Training_Time",
col="green",
ylim=c(min(datos$Training_Time, na.rm = TRUE) - 1, max(datos$Training_Time, na.rm = TRUE) + 1),
cex.main=1.5,
cex.lab=1.2,
cex.axis=1,
outline=TRUE)