Introducción al contexto del problema

El uso de algoritmos de aprendizaje automático en el procesamiento de imágenes ha adquirido gran relevancia en aplicaciones diversas, como la medicina, la seguridad y la industria automotriz. Con el aumento en el tamaño y complejidad de los conjuntos de datos de imágenes, es fundamental optimizar tanto el rendimiento, medido a través del F1 Score, como el tiempo de entrenamiento. El F1 Score es una métrica clave que combina precisión y recall, permitiendo una evaluación equilibrada del rendimiento de los modelos.

Objetivo

En este contexto, es crucial identificar los algoritmos más eficaces para maximizar el F1 Score mientras se minimiza el tiempo de entrenamiento. Esta investigación se enfoca en analizar diferentes algoritmos de inteligencia artificial, como K-Means, Neural network, Random Forest, y SVM con el objetivo de responder a la siguiente pregunta: ¿Qué algoritmo maximiza el F1 Score y minimiza el tiempo de entrenamiento al utilizar conjuntos de datos de imágenes?

Cargar base de datos y paquetes necesarios

library(readxl)
library(kableExtra)
library(ggplot2)
library(dplyr)
## 
## Adjuntando el paquete: 'dplyr'
## The following object is masked from 'package:kableExtra':
## 
##     group_rows
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(tidyr)

datos<- read_excel("D:/Usuario windows/Downloads/Dataset_IA_corte_II.xlsx")
View(datos)

summary(datos)
##   Algorithm          Framework         Problem_Type       Dataset_Type      
##  Length:560         Length:560         Length:560         Length:560        
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##     Accuracy        Precision          Recall          F1_Score     
##  Min.   :0.5038   Min.   :0.4019   Min.   :0.3001   Min.   :0.4000  
##  1st Qu.:0.6236   1st Qu.:0.5632   1st Qu.:0.4819   1st Qu.:0.5515  
##  Median :0.7578   Median :0.7195   Median :0.6493   Median :0.7086  
##  Mean   :0.8779   Mean   :0.8129   Mean   :0.7486   Mean   :0.8122  
##  3rd Qu.:0.8824   3rd Qu.:0.8596   3rd Qu.:0.8404   3rd Qu.:0.8438  
##  Max.   :9.7181   Max.   :9.7320   Max.   :9.3662   Max.   :9.3740  
##  NA's   :39       NA's   :19       NA's   :20       NA's   :20      
##  Training_Time          Date                       
##  Min.   : 0.1032   Min.   :2023-03-08 11:26:21.07  
##  1st Qu.: 1.2441   1st Qu.:2023-07-26 05:26:21.07  
##  Median : 2.4347   Median :2023-12-12 23:26:21.07  
##  Mean   : 2.9910   Mean   :2023-12-12 23:26:21.07  
##  3rd Qu.: 3.8131   3rd Qu.:2024-04-30 17:26:21.07  
##  Max.   :46.9856   Max.   :2024-09-17 11:26:21.07  
##  NA's   :20
str(datos)
## tibble [560 × 10] (S3: tbl_df/tbl/data.frame)
##  $ Algorithm    : chr [1:560] "SVM" "K-Means" "Neural Network" "SVM" ...
##  $ Framework    : chr [1:560] "Scikit-learn" "Keras" "Keras" "Keras" ...
##  $ Problem_Type : chr [1:560] "Regression" "Clustering" "Clustering" "Clustering" ...
##  $ Dataset_Type : chr [1:560] "Time Series" "Time Series" "Image" "Text" ...
##  $ Accuracy     : num [1:560] 0.662 0.744 0.885 0.842 0.723 ...
##  $ Precision    : num [1:560] 0.693 0.49 0.595 0.842 0.686 ...
##  $ Recall       : num [1:560] NA 0.877 0.969 0.875 0.301 ...
##  $ F1_Score     : num [1:560] 0.443 0.441 0.964 0.704 0.646 ...
##  $ Training_Time: num [1:560] 4.98 NA 3.28 4.04 3.6 ...
##  $ Date         : POSIXct[1:560], format: "2023-03-08 11:26:21" "2023-03-09 11:26:21" ...
head(datos)
## # A tibble: 6 × 10
##   Algorithm      Framework   Problem_Type Dataset_Type Accuracy Precision Recall
##   <chr>          <chr>       <chr>        <chr>           <dbl>     <dbl>  <dbl>
## 1 SVM            Scikit-lea… Regression   Time Series     0.662     0.693 NA    
## 2 K-Means        Keras       Clustering   Time Series     0.744     0.490  0.877
## 3 Neural Network Keras       Clustering   Image           0.885     0.595  0.969
## 4 SVM            Keras       Clustering   Text            0.842     0.842  0.875
## 5 SVM            Scikit-lea… Regression   Tabular         0.723     0.686  0.301
## 6 K-Means        PyTorch     Regression   Image           0.637     0.626  7.45 
## # ℹ 3 more variables: F1_Score <dbl>, Training_Time <dbl>, Date <dttm>
dim(datos)
## [1] 560  10
colnames(datos)
##  [1] "Algorithm"     "Framework"     "Problem_Type"  "Dataset_Type" 
##  [5] "Accuracy"      "Precision"     "Recall"        "F1_Score"     
##  [9] "Training_Time" "Date"

Tratamiento de datos n/a t outliners

# Contar la cantidad de NAs en cada columna
na_counts <- colSums(is.na(datos))

# Crear un data frame con las variables y la cantidad de NAs
na_data <- data.frame(Variable = names(na_counts), NA_Count = na_counts)

# Crear el gráfico de barras usando ggplot2
ggplot(na_data, aes(x = reorder(Variable, -NA_Count), y = NA_Count)) +
  geom_bar(stat = "identity", fill = "steelblue") +
  labs(title = "Cantidad de valores NA por variable", x = "Variable", y = "Cantidad de NA") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Lista de variables cuantitativas, excluyendo "Training_Time"
variables_cuantitativas <- c("Accuracy", "Precision", "Recall", "F1_Score")
# Eliminar las filas con NAs
datos_sin_na <- na.omit(datos)


# Crear una copia del dataset sin NAs para imputar
datos_imputados <- datos_sin_na

# Imputar outliers usando percentiles 5 y 95
for (var in variables_cuantitativas) {
  # Calcular los percentiles 5 y 95
  caps <- quantile(datos_imputados[[var]], probs = c(0.05, 0.95), na.rm = TRUE)
  
  # Calcular el rango intercuartil (IQR)
  H <- 1.5 * IQR(datos_imputados[[var]], na.rm = TRUE)
  
  # Imputar valores fuera de los límites
  datos_imputados[[var]][datos_imputados[[var]] < (caps[1] - H)] <- caps[1]
  datos_imputados[[var]][datos_imputados[[var]] > (caps[2] + H)] <- caps[2]
}

# Ver los datos limpios después de la imputación
View(datos_imputados)
dim(datos_imputados)
## [1] 448  10
summary(datos_imputados)
##   Algorithm          Framework         Problem_Type       Dataset_Type      
##  Length:448         Length:448         Length:448         Length:448        
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##     Accuracy        Precision          Recall          F1_Score     
##  Min.   :0.5038   Min.   :0.4031   Min.   :0.3001   Min.   :0.4000  
##  1st Qu.:0.6183   1st Qu.:0.5661   1st Qu.:0.4898   1st Qu.:0.5486  
##  Median :0.7490   Median :0.7275   Median :0.6513   Median :0.7031  
##  Mean   :0.7507   Mean   :0.7154   Mean   :0.6573   Mean   :0.6955  
##  3rd Qu.:0.8698   3rd Qu.:0.8670   3rd Qu.:0.8365   3rd Qu.:0.8396  
##  Max.   :0.9997   Max.   :0.9990   Max.   :0.9985   Max.   :0.9993  
##  Training_Time          Date                       
##  Min.   : 0.1032   Min.   :2023-03-10 11:26:21.07  
##  1st Qu.: 1.2982   1st Qu.:2023-08-02 23:26:21.07  
##  Median : 2.4809   Median :2023-12-24 23:26:21.07  
##  Mean   : 3.0598   Mean   :2023-12-19 17:35:59.65  
##  3rd Qu.: 3.8446   3rd Qu.:2024-05-07 05:26:21.07  
##  Max.   :46.9856   Max.   :2024-09-17 11:26:21.07
# Clasificar las variables como cuantitativas o cualitativas
tipo_variable <- ifelse(sapply(datos_imputados, is.numeric), "Cuantitativa", "Cualitativa")

# Asignar las frecuencias según el tipo de variable
frecuencias <- ifelse(tipo_variable == "Cualitativa", "Sí", "Agrupadas")

# Asignar las medidas de localización según el tipo de variable
medidas_localizacion <- ifelse(tipo_variable == "Cualitativa", "Moda", "Media, Mediana, Moda")

# Asignar otras columnas de manera similar o con ajustes según sea necesario
medidas_dispersion <- ifelse(tipo_variable == "Cuantitativa", "Desviación estándar, Rango intercuartílico", "N/A")
medidas_distribucion <- ifelse(tipo_variable == "Cuantitativa", "Asimetría, Curtosis", "N/A")
graficos <- ifelse(tipo_variable == "Cuantitativa", "Histograma, Boxplot", "Gráfico de barras")

# Crear la tabla de operacionalización sin la columna "Nombre Variable"
tabla_operacionalizacion <- data.frame(
  Naturaleza_Variable = tipo_variable,
  Escala_de_Medidas = ifelse(tipo_variable == "Cuantitativa", "Razón", "Nominal"),
  Frecuencias = frecuencias,
  Medidas_Localizacion = medidas_localizacion,
  Medidas_Dispersion = medidas_dispersion,
  Medidas_Distribucion = medidas_distribucion,
  Graficos_Sugeridos = graficos,
  stringsAsFactors = FALSE # Evitar que las cadenas se conviertan en factores
)

# Mostrar la tabla con formato gráfico usando kableExtra
tabla_operacionalizacion %>%
  kbl(caption = "Tabla de Operacionalización de Variables", escape = FALSE) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = FALSE) %>%
  column_spec(1, bold = TRUE, color = "white", background = "#4CAF50") %>%
  column_spec(2:7, background = "#f0f0f0")
Tabla de Operacionalización de Variables
Naturaleza_Variable Escala_de_Medidas Frecuencias Medidas_Localizacion Medidas_Dispersion Medidas_Distribucion Graficos_Sugeridos
Algorithm Cualitativa Nominal Moda N/A N/A Gráfico de barras
Framework Cualitativa Nominal Moda N/A N/A Gráfico de barras
Problem_Type Cualitativa Nominal Moda N/A N/A Gráfico de barras
Dataset_Type Cualitativa Nominal Moda N/A N/A Gráfico de barras
Accuracy Cuantitativa Razón Agrupadas Media, Mediana, Moda Desviación estándar, Rango intercuartílico Asimetría, Curtosis Histograma, Boxplot
Precision Cuantitativa Razón Agrupadas Media, Mediana, Moda Desviación estándar, Rango intercuartílico Asimetría, Curtosis Histograma, Boxplot
Recall Cuantitativa Razón Agrupadas Media, Mediana, Moda Desviación estándar, Rango intercuartílico Asimetría, Curtosis Histograma, Boxplot
F1_Score Cuantitativa Razón Agrupadas Media, Mediana, Moda Desviación estándar, Rango intercuartílico Asimetría, Curtosis Histograma, Boxplot
Training_Time Cuantitativa Razón Agrupadas Media, Mediana, Moda Desviación estándar, Rango intercuartílico Asimetría, Curtosis Histograma, Boxplot
Date Cualitativa Nominal Moda N/A N/A Gráfico de barras

Grafico de distribucion antes y despues de elminar los datos NA

# Definir la función para hacer histogramas de las variables antes y después de eliminar NAs
plot_distribution <- function(datos, datos_sin_na, var_name) {
  # Verificar que la variable existe en ambos dataframes
  if (!(var_name %in% colnames(datos)) || !(var_name %in% colnames(datos_sin_na))) {
    stop(paste("La variable", var_name, "no existe en uno de los dataframes."))
  }
  
  # Graficar la distribución antes de eliminar los NAs
  p1 <- ggplot(datos, aes(x = .data[[var_name]])) +
    geom_histogram(bins = 30, fill = "blue", alpha = 0.7, color = "black") +
    ggtitle(paste("Distribucion de", var_name, "antes de eliminar NA")) +  # Título sin acentos
    labs(x = var_name, y = "Frecuencia") +
    theme_minimal()
  
  # Graficar la distribución después de eliminar los NAs
  p2 <- ggplot(datos_sin_na, aes(x = .data[[var_name]])) +
    geom_histogram(bins = 30, fill = "green", alpha = 0.7, color = "black") +
    ggtitle(paste("Distribucion de", var_name, "despues de eliminar NA")) +  # Título sin acentos
    labs(x = var_name, y = "Frecuencia") +
    theme_minimal()
  
  # Mostrar ambas gráficas
  print(p1)
  print(p2)
}

# Supongamos que ya tienes definidos 'datos' y 'datos_sin_na'
# datos <- datos  # Dataset original con NAs
# datos_sin_na <- datos %>% drop_na()  # Dataset después de eliminar los NAs

# Listado de las columnas numéricas que quieres analizar
variables <- c("Accuracy", "Precision", "Recall", "F1_Score", "Training_Time")

# Graficar las distribuciones antes y después de eliminar los NA por cada variable
for (var in variables) {
  plot_distribution(datos, datos_sin_na, var)
}
## Warning: Removed 39 rows containing non-finite outside the scale range
## (`stat_bin()`).

## Warning: Removed 19 rows containing non-finite outside the scale range
## (`stat_bin()`).

## 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_bin()`).

## Warning: Removed 20 rows containing non-finite outside the scale range
## (`stat_bin()`).

Analisis de datos cualitativos

# Cargar la librería necesaria
library(ggplot2)

# Variables cualitativas a graficar
variables_cualitativas <- c("Algorithm", "Dataset_Type", "Problem_Type", "Framework")

# Crear un gráfico de barras para cada variable cualitativa
for (var in variables_cualitativas) {
  # Crear el gráfico
  p <- ggplot(datos_imputados, aes_string(x = var)) +
    geom_bar(fill = "lightgreen", color = "black") +  # Cambiar el color de las barras a rojo
    labs(title = paste("Frecuencia  de", var),
         x = var,
         y = "Frecuencia") +
    theme_minimal() +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))  # Mejorar la legibilidad del texto
  
  # Mostrar el gráfico
  print(p)
}
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## ℹ Please use tidy evaluation idioms with `aes()`.
## ℹ See also `vignette("ggplot2-in-packages")` for more information.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Analisis de datos cuantitativos

datos_cuantitativos <- datos_imputados %>% 
  select(c("Accuracy", "Precision", "Recall", "F1_Score", "Training_Time"))  # Cambia o agrega más variables si es necesario

# Aplicar la prueba de Shapiro-Wilk a cada variable cuantitativa y mostrar los resultados
for (var in colnames(datos_cuantitativos)) {
  shapiro_test <- shapiro.test(datos_cuantitativos[[var]])
  
  # Imprimir resultados de forma clara
  cat("Variable:", var, "\n")
  cat("Estadístico W:", shapiro_test$statistic, "\n")
  cat("Valor p:", shapiro_test$p.value, "\n\n")
}
## Variable: Accuracy 
## Estadístico W: 0.9520618 
## Valor p: 7.077009e-11 
## 
## Variable: Precision 
## Estadístico W: 0.9508405 
## Valor p: 4.759494e-11 
## 
## Variable: Recall 
## Estadístico W: 0.9514646 
## Valor p: 5.82432e-11 
## 
## Variable: F1_Score 
## Estadístico W: 0.956087 
## Valor p: 2.74439e-10 
## 
## Variable: Training_Time 
## Estadístico W: 0.3397098 
## Valor p: 3.462549e-37
# Cargar las librerías necesarias
library(dplyr)
library(ggplot2)

# Seleccionar las variables cuantitativas
datos_cuantitativos <- datos_imputados %>%
  select(where(is.numeric))  # Seleccionar solo las variables numéricas

# Crear histogramas para cada variable cuantitativa
for (var in names(datos_cuantitativos)) {
  p <- ggplot(datos_cuantitativos, aes_string(x = var)) +
    geom_histogram(binwidth = 0.2, fill = "blue", color = "black", alpha = 0.7) +
    labs(title = paste("Histograma de", var),
         x = var,
         y = "Frecuencia") +
    theme_minimal() +
    theme(axis.text.x = element_text(angle = 45, hjust = 1)) 
  
  print(p)  # Mostrar el gráfico
}

Los graficos anteriores muestran que ninguna de las variables cuantitativas sigue una distribucion normal a partir de los histogramas y tambien por la shapiro wilk test nos ayudo con el valor p a comprobar que no tienen una distribucion normal.Porque los valores que nos dan no son cercanos a 1.

# Seleccionar las variables cuantitativas excluyendo 'Training_Time'
datos_cuantitativos <- datos_imputados %>%
  select(where(is.numeric)) %>%
  select(-Training_Time)  # Eliminar 'Training_Time'

# Transformar los datos a formato largo
datos_long <- datos_cuantitativos %>%
  pivot_longer(cols = everything(), names_to = "Variable", values_to = "Valor")

# Crear el boxplot
ggplot(datos_long, aes(x = Variable, y = Valor, fill = Variable)) +
  geom_boxplot() +
  labs(title = "Boxplot de Variables Cuantitativas ",
       x = "Variables",
       y = "Valor") +
  theme_minimal() +
  theme(legend.position = "none",  # Quitar la leyenda
        axis.text.x = element_text(angle = 45, hjust = 1))  # Mejorar la legibilidad del texto

# Crear el boxplot para Training_Time sin la línea de la mediana
ggplot(datos_imputados, aes(x = "", y = Training_Time)) +
  geom_boxplot(fill = "steelblue", color = "black", width = 0.5) + # Aumentar el ancho
  labs(title = "Boxplot de Training Time",
       x = "Training Time",
       y = "Valor (Segundos)") +
  theme_minimal() +
  theme(axis.title.x = element_blank(),  # Quitar el título del eje x
        axis.text.x = element_blank(),   # Quitar las etiquetas del eje x
        axis.ticks.x = element_blank(),  # Quitar los ticks del eje x
        axis.text.y = element_text(size = 12),  # Aumentar el tamaño del texto en el eje y
        axis.title.y = element_text(size = 14)) + # Aumentar el tamaño del título del eje y
  coord_cartesian(ylim = c(0, max(datos_imputados$Training_Time, na.rm = TRUE) + 10)) # Ajustar límites del eje y

Los boxplots nos muestran los cuartiles de cada variable cuantitativa despues de la limpieza de na y de los valores atipicos tambien nos muestra la mediana que es la que nos ayuda a sacar conclusion porque no siguen una distribucion normal y no se puede llegar a una conclusion a partir de la media.

library(dplyr)
summary(datos_cuantitativos)
##     Accuracy        Precision          Recall          F1_Score     
##  Min.   :0.5038   Min.   :0.4031   Min.   :0.3001   Min.   :0.4000  
##  1st Qu.:0.6183   1st Qu.:0.5661   1st Qu.:0.4898   1st Qu.:0.5486  
##  Median :0.7490   Median :0.7275   Median :0.6513   Median :0.7031  
##  Mean   :0.7507   Mean   :0.7154   Mean   :0.6573   Mean   :0.6955  
##  3rd Qu.:0.8698   3rd Qu.:0.8670   3rd Qu.:0.8365   3rd Qu.:0.8396  
##  Max.   :0.9997   Max.   :0.9990   Max.   :0.9985   Max.   :0.9993
summary_stats <- datos_cuantitativos %>%
  summarise(
    Desviacion_Estandar_Accuracy = sd(Accuracy),
    Varianza_Accuracy = var(Accuracy),
    Desviacion_Estandar_Precision = sd(Precision),
    Varianza_Precision = var(Precision),
    Desviacion_Estandar_Recall = sd(Recall),
    Varianza_Recall = var(Recall),
    
  )

# Mostrar los resultados
print(summary_stats)
## # A tibble: 1 × 6
##   Desviacion_Estandar_Accuracy Varianza_Accuracy Desviacion_Estandar_Precision
##                          <dbl>             <dbl>                         <dbl>
## 1                        0.147            0.0216                         0.174
## # ℹ 3 more variables: Varianza_Precision <dbl>,
## #   Desviacion_Estandar_Recall <dbl>, Varianza_Recall <dbl>

Analisis Bivariado

# Cargar librerías necesarias
library(ggplot2)
library(dplyr)

# Filtrar los datos para obtener solo los del tipo "Image"
datos_imagenes <- datos_imputados %>%
  filter(Dataset_Type == "Image")  # Asegúrate de que 'Dataset_Type' sea el nombre correcto

# Verificar las primeras filas de datos_imagenes para confirmar la estructura
head(datos_imagenes)
## # A tibble: 6 × 10
##   Algorithm      Framework   Problem_Type Dataset_Type Accuracy Precision Recall
##   <chr>          <chr>       <chr>        <chr>           <dbl>     <dbl>  <dbl>
## 1 Neural Network Keras       Clustering   Image           0.885     0.595  0.969
## 2 K-Means        PyTorch     Regression   Image           0.637     0.626  0.976
## 3 Neural Network Scikit-lea… Regression   Image           0.713     0.676  0.480
## 4 SVM            PyTorch     Regression   Image           0.897     0.982  0.781
## 5 SVM            Keras       Clustering   Image           0.847     0.872  0.380
## 6 SVM            PyTorch     Clustering   Image           0.541     0.813  0.619
## # ℹ 3 more variables: F1_Score <dbl>, Training_Time <dbl>, Date <dttm>
# Agrupar por intervalos de tiempo y calcular el promedio de F1_Score
datos_agrupados <- datos_imagenes %>%
  mutate(Training_Time_Group = cut(Training_Time, breaks = 5, labels = paste0("Grupo ", 1:5))) %>%
  group_by(Training_Time_Group, Algorithm) %>%
  summarize(F1_Score = mean(F1_Score, na.rm = TRUE), .groups = 'drop')

# Verificar la estructura de datos_agrupados
head(datos_agrupados)
## # A tibble: 6 × 3
##   Training_Time_Group Algorithm      F1_Score
##   <fct>               <chr>             <dbl>
## 1 Grupo 1             K-Means           0.788
## 2 Grupo 1             Neural Network    0.648
## 3 Grupo 1             Random Forest     0.503
## 4 Grupo 1             SVM               0.834
## 5 Grupo 2             K-Means           0.666
## 6 Grupo 2             Neural Network    0.512
# Crear el gráfico de líneas
ggplot(datos_agrupados, aes(x = Training_Time_Group, y = F1_Score, color = Algorithm)) +
  geom_line(size = 1, aes(group = Algorithm)) +  # Trazar líneas para cada algoritmo
  geom_point(size = 2) +  # Agregar puntos en las líneas
  geom_smooth(se = FALSE, method = "loess") +  # Línea de suavizado
  labs(title = "F1 Score Promedio vs. Intervalos de Tiempo de Entrenamiento por Algoritmo",
       x = "Intervalo de Tiempo de Entrenamiento",
       y = "F1 Score Promedio") +
  theme_minimal() +
  theme(legend.title = element_blank()) +  # Eliminar el título de la leyenda
  scale_color_manual(values = c("red", "green", "blue", "purple"))  # Asignar colores específicos
## 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.
## `geom_smooth()` using formula = 'y ~ x'

Hallazgos del grafico de lineas

Se visualizan las tendencias del F1 Score promedio de cada algoritmo agrupado por intervalos de tiempo de entrenamiento. La línea correspondiente al SVM se destaca al mostrar consistentemente el mayor F1 Score en los intervalos donde era menor el tiempo, lo que sugiere que es el algoritmo más eficiente para maximizar el rendimiento en un periodo menor. Así como en la grafica de dispersión, a medida que se incrementa el tiempo de entrenamiento, se observa que otros algoritmos, aunque logran alcanzar un rendimiento comparable, requieren tiempos significativamente mayores, lo que subraya la superioridad del SVM en términos de rapidez y efectividad.

# Crear el gráfico de dispersión
  ggplot(datos_imagenes, aes(x = Training_Time, y = F1_Score, color = Algorithm)) +
    geom_point(size = 3) +                  # Puntos del gráfico
    geom_smooth(method = "lm", se = FALSE) + # Línea de tendencia
    labs(title = "Relación entre F1 Score y Tiempo de Entrenamiento (Conjuntos de Datos de Imágenes)",
         x = "Tiempo de Entrenamiento (segundos)",
         y = "F1 Score") +
    theme_minimal() +                        # Tema minimalista
    theme(legend.title = element_blank())    # Sin título en la leyenda
## `geom_smooth()` using formula = 'y ~ x'

Hallazgo de el grafico de dispersion

La línea trazada en el gráfico de dispersión, obtenida a partir de un modelo de regresión, indica que el algoritmo SVM presenta un F1 Score mayor en menor tiempo de entrenamiento, a diferencia de otros algoritmos que requieren más tiempo para alcanzar niveles similares de rendimiento. Además, se observa que, a medida que aumenta el tiempo de entrenamiento, el F1 Score del SVM tiende a disminuir, lo que sugiere que la eficiencia del SVM podría verse comprometida con tiempos de entrenamiento prolongados.

Conclusion

El análisis exploratorio revela que el algoritmo SVM es el más eficiente para maximizar el F1 Score en períodos cortos de entrenamiento, superando a otros algoritmos como K-Means, Redes Neuronales y Random Forest. Sin embargo, se descubrió que las variables cuantitativas no presentan una distribución normal, lo que podría influir en la interpretación de los resultados.

A pesar de que el SVM logra altos rendimientos inicialmente, su F1 Score tiende a disminuir con tiempos de entrenamiento prolongados, lo que sugiere que su eficacia puede verse comprometida. Esta información es crucial para responder a nuestra pregunta planteada: el SVM se destaca como el algoritmo que maximiza el F1 Score y minimiza el tiempo de entrenamiento en el procesamiento de imágenes. Este hallazgo enfatiza la importancia de equilibrar el tiempo de entrenamiento y el rendimiento, siendo fundamental para aplicaciones en áreas como la medicina y la seguridad. Note that the echo = FALSE parameter was added to the code chunk to prevent printing of the R code

that generated the plot.