Sys.setlocale("LC_ALL", "es_ES.UTF-8")
[1] "LC_COLLATE=es_ES.UTF-8;LC_CTYPE=es_ES.UTF-8;LC_MONETARY=es_ES.UTF-8;LC_NUMERIC=C;LC_TIME=es_ES.UTF-8"

RESPONDER A LAS SIGUIENTES CUESTIONES RELACIONADAS CON EL DATASET lung_cancer.csv

Primero se presenta el dataset que vamos a utilizar para responder a las cuestiones planteadas y se arreglará para poder trabajar con éLungC. El dataset lung_cancer.csv contiene datos sobre pacientes con y sin cáncer de pulmón.

Las variables que se incluyen son:

Variable Descripción
Género M(Masculino), F(Femenino)
Edad Edad del paciente
Fumador SI = 2, NO = 1
Dedos Amarillos SI = 2, NO = 1
Ansiedad SI = 2, NO = 1
Presión de Pares SI = 2, NO = 1
Enfermedad Crónica SI = 2, NO = 1
Fatiga SI = 2, NO = 1
Alergia SI = 2, NO = 1
Sibilancias SI = 2, NO = 1
Alcohol SI = 2, NO = 1
Tos SI = 2, NO = 1
Dificultad para Respirar SI = 2, NO = 1
Dificultad para Tragar SI = 2, NO = 1
Dolor en el Pecho SI = 2, NO = 1
Cáncer de Pulmón SI, NO

Aquí tenemos una descripción de los datos

LungC = readr::read_csv("lung_cancer.csv")
LungC = data.frame(LungC)

str(LungC)
'data.frame':   309 obs. of  16 variables:
 $ GENDER               : chr  "M" "M" "F" "M" ...
 $ AGE                  : num  69 74 59 63 63 75 52 51 68 53 ...
 $ SMOKING              : num  1 2 1 2 1 1 2 2 2 2 ...
 $ YELLOW_FINGERS       : num  2 1 1 2 2 2 1 2 1 2 ...
 $ ANXIETY              : num  2 1 1 2 1 1 1 2 2 2 ...
 $ PEER_PRESSURE        : num  1 1 2 1 1 1 1 2 1 2 ...
 $ CHRONIC.DISEASE      : num  1 2 1 1 1 2 1 1 1 2 ...
 $ FATIGUE              : num  2 2 2 1 1 2 2 2 2 1 ...
 $ ALLERGY              : num  1 2 1 1 1 2 1 2 1 2 ...
 $ WHEEZING             : num  2 1 2 1 2 2 2 1 1 1 ...
 $ ALCOHOL.CONSUMING    : num  2 1 1 2 1 1 2 1 1 2 ...
 $ COUGHING             : num  2 1 2 1 2 2 2 1 1 1 ...
 $ SHORTNESS.OF.BREATH  : num  2 2 2 1 2 2 2 2 1 1 ...
 $ SWALLOWING.DIFFICULTY: num  2 2 1 2 1 1 1 2 1 2 ...
 $ CHEST.PAIN           : num  2 2 2 2 1 1 2 1 1 2 ...
 $ LUNG_CANCER          : chr  "YES" "YES" "NO" "NO" ...

Vemos efectivamente que la base de datos contiene las 16 variables en un total de 309 pacientes. Vamos a establecer la categoría correcta de cada variable(factor/numérica), vamos a añadir las etiquetas correspondientes a la leyenda facilitada y vamos a homogeneizar los nombres de las variables.

names(LungC) = c("GENDER", "AGE", "SMOKING", "YELLOW_FINGERS", "ANXIETY", "PEER_PRESSURE", "CHRONIC_DISEASE", "FATIGUE", "ALLERGY", "WHEEZING", "ALCOHOL_CONSUMING", "COUGHING", "SHORTNESS_OF_BREATH", "SWALLOWING_DIFFICULTY", "CHEST_PAIN", "LUNG_CANCER")

category_cols = c("GENDER", "SMOKING", "YELLOW_FINGERS", "ANXIETY", "PEER_PRESSURE", "CHRONIC_DISEASE", "FATIGUE", "ALLERGY", "WHEEZING", "ALCOHOL_CONSUMING", "COUGHING", "SHORTNESS_OF_BREATH", "SWALLOWING_DIFFICULTY", "CHEST_PAIN", "LUNG_CANCER")

for(col in category_cols) {
  LungC[[col]] = as.factor(LungC[[col]])
}

# 
# LungC$SMOKING <- factor(LungC$SMOKING,
#                    levels = c(1, 2),
#                    labels = c("No", "Si"))
# 
# LungC$YELLOW_FINGERS <- factor(LungC$YELLOW_FINGERS,
#                           levels = c(1, 2),
#                           labels = c("No", "Si"))
# 
# LungC$ANXIETY <- factor(LungC$ANXIETY,
#                    levels = c(1, 2),
#                    labels = c("No", "Si"))
# 
# LungC$PEER_PRESSURE <- factor(LungC$PEER_PRESSURE,
#                          levels = c(1, 2),
#                          labels = c("No", "Si"))
# 
# LungC$CHRONIC_DISEASE <- factor(LungC$CHRONIC_DISEASE,
#                             levels = c(1, 2),
#                             labels = c("No", "Si"))
# 
# LungC$FATIGUE <- factor(LungC$FATIGUE,
#                    levels = c(1, 2),
#                    labels = c("No", "Si"))
# 
# LungC$ALLERGY <- factor(LungC$ALLERGY,
#                    levels = c(1, 2),
#                    labels = c("No", "Si"))
# 
# LungC$WHEEZING <- factor(LungC$WHEEZING,
#                     levels = c(1, 2),
#                     labels = c("No", "Si"))
# 
# LungC$ALCOHOL_CONSUMING <- factor(LungC$ALCOHOL_CONSUMING,
#                               levels = c(1, 2),
#                               labels = c("No", "Si"))
# 
# LungC$COUGHING <- factor(LungC$COUGHING,
#                     levels = c(1, 2),
#                     labels = c("No", "Si"))
# 
# LungC$SHORTNESS_OF_BREATH <- factor(LungC$SHORTNESS_OF_BREATH,
#                                levels = c(1, 2),
#                                labels = c("No", "Si"))
# 
# LungC$SWALLOWING_DIFFICULTY <- factor(LungC$SWALLOWING_DIFFICULTY,
#                                  levels = c(1, 2),
#                                  labels = c("No", "Si"))
# 
# LungC$CHEST_PAIN <- factor(LungC$CHEST_PAIN,
#                       levels = c(1, 2),
#                       labels = c("No", "Si"))


for(col in category_cols[category_cols != "LUNG_CANCER" & category_cols != "GENDER"]) {
  LungC[[col]] <- factor(LungC[[col]],
                   levels = c(1, 2),
                   labels = c("No", "Si"))
}

str(LungC)
'data.frame':   309 obs. of  16 variables:
 $ GENDER               : Factor w/ 2 levels "F","M": 2 2 1 2 1 1 2 1 1 2 ...
 $ AGE                  : num  69 74 59 63 63 75 52 51 68 53 ...
 $ SMOKING              : Factor w/ 2 levels "No","Si": 1 2 1 2 1 1 2 2 2 2 ...
 $ YELLOW_FINGERS       : Factor w/ 2 levels "No","Si": 2 1 1 2 2 2 1 2 1 2 ...
 $ ANXIETY              : Factor w/ 2 levels "No","Si": 2 1 1 2 1 1 1 2 2 2 ...
 $ PEER_PRESSURE        : Factor w/ 2 levels "No","Si": 1 1 2 1 1 1 1 2 1 2 ...
 $ CHRONIC_DISEASE      : Factor w/ 2 levels "No","Si": 1 2 1 1 1 2 1 1 1 2 ...
 $ FATIGUE              : Factor w/ 2 levels "No","Si": 2 2 2 1 1 2 2 2 2 1 ...
 $ ALLERGY              : Factor w/ 2 levels "No","Si": 1 2 1 1 1 2 1 2 1 2 ...
 $ WHEEZING             : Factor w/ 2 levels "No","Si": 2 1 2 1 2 2 2 1 1 1 ...
 $ ALCOHOL_CONSUMING    : Factor w/ 2 levels "No","Si": 2 1 1 2 1 1 2 1 1 2 ...
 $ COUGHING             : Factor w/ 2 levels "No","Si": 2 1 2 1 2 2 2 1 1 1 ...
 $ SHORTNESS_OF_BREATH  : Factor w/ 2 levels "No","Si": 2 2 2 1 2 2 2 2 1 1 ...
 $ SWALLOWING_DIFFICULTY: Factor w/ 2 levels "No","Si": 2 2 1 2 1 1 1 2 1 2 ...
 $ CHEST_PAIN           : Factor w/ 2 levels "No","Si": 2 2 2 2 1 1 2 1 1 2 ...
 $ LUNG_CANCER          : Factor w/ 2 levels "NO","YES": 2 2 1 1 1 2 2 2 1 2 ...

Presentación de los datos con una tabla interactiva

LungC = LungC %>%
  mutate(
    LUNG_CANCER = as.factor(dplyr::recode(LUNG_CANCER, 'NO'= "No", 'YES' = "Si") ),
    GENDER = as.factor(dplyr::recode(GENDER, 'M'= "Hombre", 'F' = "Mujer")
                        )) %>%
  relocate(LUNG_CANCER, .before = GENDER)

DT::datatable(LungC,
              rownames = TRUE, # Muestra los nombres de las filas
              options = list(pageLength = 10, # Establece el número de filas visibles por página
                              scrollX = TRUE),# Habilita la barra de desplazamiento horizontal si es necesaria
              class = "white-space: nowrap")# Evita que el texto se divida en varias lineas dentro de las celdas

Vamos a determinar si alguna de las variables factor tiene algún dato que le falte(n_missing).

DF = skim(LungC) %>%
  yank("factor") #%>%
  # mutate(
  #   mean = round(mean, 2), # Redondea la media a 2 decimales
  #   sd = round(sd, 2) # Redondea la desviación estándar a 2 decimales
  #   )
# Crear una tabla visual con formato mejorado para mostrar la estadística descriptiva de las variables factoriales
DF %>%
  kable() %>% # Convierte la tabla en formato HTML o LaTeX para visualización
  add_header_above(c("Descriptiva de las variables factoriales" = 6),
                    color = "black", bold = TRUE, font_size = 18) %>% # Agrega un encabezado superior

kable_styling("striped", # Aplica un estilo de rayas para mejor lectura
               full_width = FALSE, # Limita el ancho de la tabla al contenido
               position = "center", # Centra la tabla en el documento
               font_size = 16) %>%
  column_spec(1, bold = TRUE) %>% # Hace que la primera columna sea negrita
  row_spec(0, bold = TRUE, color = "orange") # Resalta la primera fila en color naranja y en negrita
Descriptiva de las variables factoriales
skim_variable n_missing complete_rate ordered n_unique top_counts
LUNG_CANCER 0 1 FALSE 2 Si: 270, No: 39
GENDER 0 1 FALSE 2 Hom: 162, Muj: 147
SMOKING 0 1 FALSE 2 Si: 174, No: 135
YELLOW_FINGERS 0 1 FALSE 2 Si: 176, No: 133
ANXIETY 0 1 FALSE 2 No: 155, Si: 154
PEER_PRESSURE 0 1 FALSE 2 Si: 155, No: 154
CHRONIC_DISEASE 0 1 FALSE 2 Si: 156, No: 153
FATIGUE 0 1 FALSE 2 Si: 208, No: 101
ALLERGY 0 1 FALSE 2 Si: 172, No: 137
WHEEZING 0 1 FALSE 2 Si: 172, No: 137
ALCOHOL_CONSUMING 0 1 FALSE 2 Si: 172, No: 137
COUGHING 0 1 FALSE 2 Si: 179, No: 130
SHORTNESS_OF_BREATH 0 1 FALSE 2 Si: 198, No: 111
SWALLOWING_DIFFICULTY 0 1 FALSE 2 No: 164, Si: 145
CHEST_PAIN 0 1 FALSE 2 Si: 172, No: 137

Vamos a determinar si alguna de las variables numéricas tiene algún dato que le falte(n_missing) y obtener las frecuencias para cada una de las opciones de cada variables

DN = skim(LungC) %>%
  yank("numeric") %>% # Extrae solo las variables numericas del resumen generado por 'skim()'
  mutate(
    mean = round(mean, 2), # Redondea la media a 2 decimales
    sd = round(sd, 2) # Redondea la desviación estándar a 2 decimales
    )
# Crear una tabla visual con formato mejorado para mostrar la estadística descriptiva de las variables numéricas
DN %>%
  kable() %>% # Convierte la tabla en formato HTML o LaTeX para visualización
  add_header_above(c("Descriptiva de las variables numericas" = 11),
                    color = "black", bold = TRUE, font_size = 18) %>% # Agrega un encabezado superior

kable_styling("striped", # Aplica un estilo de rayas para mejor lectura
               full_width = FALSE, # Limita el ancho de la tabla al contenido
               position = "center", # Centra la tabla en el documento
               font_size = 16) %>%
  column_spec(1, bold = TRUE) %>% # Hace que la primera columna sea negrita
  row_spec(0, bold = TRUE, color = "orange") # Resalta la primera fila en color naranja y en negrita
Descriptiva de las variables numericas
skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
AGE 0 1 62.67 8.21 21 57 62 69 87 ▁▁▆▇▂

Y otra manera de ver los datos ausentes dentro de la base de datos:

# Función para contar valores NA(faltantes) en cada columna del dataframe
na_values = function(x) {
  sum(is.na(x) ) # Calcula la cantidad de valores NA en un vector x
}

# Aplicar la función a cada columna del dataset 'LungC' para contar los valores NA por variable
# 'apply' recorre las columnas(MARGIN = 2) del dataframe 'LungC' y aplica la función 'na_values' en cada una.
apply(LungC, 2, na_values)
          LUNG_CANCER                GENDER                   AGE 
                    0                     0                     0 
              SMOKING        YELLOW_FINGERS               ANXIETY 
                    0                     0                     0 
        PEER_PRESSURE       CHRONIC_DISEASE               FATIGUE 
                    0                     0                     0 
              ALLERGY              WHEEZING     ALCOHOL_CONSUMING 
                    0                     0                     0 
             COUGHING   SHORTNESS_OF_BREATH SWALLOWING_DIFFICULTY 
                    0                     0                     0 
           CHEST_PAIN 
                    0 

Como podemos ver no tenemos ningún valor ausente.

Con esta base de datos preparada procederemos a realizar los análisis y los gráficos pertinentes.

REALIZAR UN ANALISIS GRAFICO DE LOS INDIVIDUOS CON/SIN CANCER DE PULMÓN

Vamos a realizar los gráficos de las distintas variables relacionándolas con si los pacientes tienen o no cáncer de pulmón. Para comparar variables factoriales realizaremos histogramas y para comparar variables numéricas utilizaremos los boxplot.

Se presentan los histogramas de manera general:

# Transformación del dataset para visualización con ggplot2
Hl = melt(LungC,
           id.var = "LUNG_CANCER", # Variable fija para comparación
           measure.vars = c("GENDER", "SMOKING", "YELLOW_FINGERS", "ANXIETY",
                             "PEER_PRESSURE", "CHRONIC_DISEASE", "FATIGUE", "ALLERGY",
                             "WHEEZING", "ALCOHOL_CONSUMING", "COUGHING",
                             "SHORTNESS_OF_BREATH", "SWALLOWING_DIFFICULTY", "CHEST_PAIN"))

# 'melt()' convierte el dataframe de formato ancho a largo para facilitar el trazado de gráficos con ggplot2.
# La variable "LUNG CANCER" se mantiene fija, y las demás se transforman en una estructura de "variable-valor".

# Creación de un gráfico de barras con ggplot2
p = ggplot(Hl, aes(x = value, fill = LUNG_CANCER)) +
  geom_bar(position = "dodge", color = "grey") + # Genera un gráfico de barras con agrupación por diagnóstico
  facet_wrap(~variable, nrow = 7, ncol = 3, scales = "free_x") + # Divide el gráfico en sub-gráficos según cada variable categórica
  labs(title = "Distribucion de las variables factoriales en función \n del diagnóstico de cáncer de pulmón",
         x = "Variable", # Etiqueta del eje X
         y = "Frecuencia", # Etiqueta del eje Y
         fill = "Diagnostico cáncer \nde pulmón") + # Leyenda del gráfico
  scale_fill_manual(values = c("No" = "lightblue", "Si" = "#FFCC99") ) + # Definir colores manualmente
  theme_grey() + # Aplicar tema gris por defecto
  theme(
    panel.spacing = unit(1, "lines"), # Ajustar el espacio entre paneles en el facetado
    axis.text.x = element_text(angle = 0, hjust = 1), # Ajuste del texto en el eje X
    strip.text = element_text(size = 10), # Tamano del texto en los paneles
    axis.title.y = element_text(size = 14), # Tamaño del titulo del eje Y
    axis.title.x = element_text(size = 14), # Tamaño del titulo del eje X
    plot.title = element_text(size = 20, hjust = 0.5) # Tamaño y alineación del titulo general del gráfico
    )

# Convertir el gráfico a una versión interactiva con plotly
# 'ggplotly() ' convierte un gráfico estático de ggplot en uno interactivo con zoom y tooltip.
p_interactive = ggplotly(p, height = 1000, width = 1000)


# Ajuste del diseño del gráfico interactivo
p_interactive = p_interactive %>% layout(
  hoverlabel = list(
    bgcolor = "black", # Color de fondo del tooltip
    font = list(color = "white") # Color del texto en el tooltip
  ),
  margin = list(LungC = 100, r = 50, b = 100, t = 150), # Ajustar los márgenes del gráfico
  xaxis = list(tickangle = 0), # Mantener etiquetas horizontales en el eje X
  yaxis = list(automargin = TRUE) # Ajuste automático del margen en el eje Y
)

# Mostrar el gráfico interactivo
p_interactive

Y se realizan los histogramas individualmente por si alguno tuera de interés:

# Crear una lista vacía para almacenar los gráficos
graf_list <- list()

# Excluir la variable "LUNG_CANCER" de la lista de variables categóricas a analizar
category_cols_H = category_cols[category_cols != "LUNG_CANCER"]

# Bucle para generar gráficos individuales para cada variable categórica
for(variable in category_cols_H) {

  # Crear un gráfico de barras con ggplot para la variable en cuestión
  G = ggplot(LungC, aes_string(x = variable)) +
    geom_bar(aes(fill = LUNG_CANCER), show.legend = TRUE, color = "grey") + # Gráfico de barras con color por diagnóstico
    facet_wrap(~ LUNG_CANCER) + # Separar los gráficos en función del diagnóstico de cáncer de pulmón
    labs(fill = "Diagnóstico cáncer \nde Pulmón") + # Etiqueta de la leyenda
    scale_fill_manual(values = c("No" = "lightblue", "Si" = "#FFCC99")) + # Definir colores personalizados
    theme_grey() # Aplicar el tema gris predeterminado

  # Convertir el gráfico a un gráfico interactivo con plotly
  GH1 = ggplotly(G, height = 300 , width = 550)

  
  # Ajustar el diseño del gráfico: interactivo
  GH1 = GH1 %>% layout(
    hoverlabel = list(
      bgcolor = "black", # Color de fondo de las etiquetas emergentes(tooltip)
      font = list(color = "white") # Color del texto en las etiquetas emergentes
      )
    )
  # Agregar el gráfico interactivo a la lista de gráficos
  graf_list[[length(graf_list) + 1]] <- GH1
}

# Mostrar todos los gráficos interactivos generados
browsable(tagList(graf_list))

Se presenta el boxplot con la única variable numérica indicando la media(rojo) y la mediana(Azul)

# Transformación del dataset para la visualización con ggplot2
Bl = melt(LungC,
          id.var = "LUNG_CANCER", # Mantener la variable LUNG_CANCER como identificador
          measure.vars = c("AGE")) # Seleccionar la variable AGE para convertir el dataframe a formato largo

# Creación de un boxplot para comparar la distribución de la edad en función del diagnóstico de cáncer de pulmón
p = ggplot(Bl, aes(x = LUNG_CANCER, y = value, fill = LUNG_CANCER)) +
  geom_boxplot() + # Crear el boxplot con relleno basado en la variable LUNG CANCER
  stat_summary(fun = median, geom = "crossbar", width = 0.75, color = "blue", size = 0.5) + # Iinea azul en la mediana
  stat_summary(fun = mean, geom = "crossbar", width = 0.75, color = "red", size = 0.5) + # Linea roja en la media
  scale_fill_manual(values = c("No" = "lightblue", "Si" = "#FFCC99") ) + # Colores personalizados para cada categoría
  theme_grey() + # Aplicar el tema gris predeterminado
  theme(
    panel.spacing = unit(1, "lines"), # Ajustar el espacio entre paneles
    axis.text.x = element_text(angle = 0, vjust = 0.5), # Ajuste del texto en el eje X
    strip.text = element_text(size = 10), # Tamano del texto en los paneles
    axis.title.y = element_text(size = 14), # Tamaño del titulo del eje Y
    axis.title.x = element_text(size = 14), # Tamaño del titulo del eje X
    plot.title = element_text(size = 18, hjust = 0.5) # Tamaño y alineación del titulo del gráfico
    ) +
  labs(title = "Boxplot de la edad en función del \ndiagnóstico de cáncer de Pulmón", # Titulo del gráfico
       x = "Cáncer de pulmón", # Etiqueta del eje X
       y = "Edad", # Etiqueta del eje Y
       fill = "Diagnostico cáncer \nde Pulmón") # Etiqueta de la leyenda

# Convertir el gráfico a una versión interactiva con plotly
p_interactive = ggplotly(p, height = 500, width = 700)

# Ajustar el diseño del gráfico interactivo
p_interactive = p_interactive %>% layout(
  hoverlabel = list(
    bgcolor = "black", # Color de fondo del tooltip
    font = list(color = "white") # Color del texto en el tooltip
    ),
  margin = list(LungC = 100, r = 50, b = 100, t = 100), # Ajustar los márgenes del gráfico
  xaxis = list(tickangle = 0), # Mantener etiquetas horizontales en el eje X
  yaxis = list(automargin = TRUE) # Ajuste automatico del margen en el eje Y
  )

# Mostrar el gráfico interactivo
p_interactive

Referente a los histogramas habría que realizar test estadísticos, como el test de chi-cuadrado, para determinar si las diferencias que observamos en los histogramas son significativas.

En relación al boxplot podemos observar la presencia de pocos outliers y podríamos realizar un test no para métrico para ver si la diferencia de edad entre los pacientes con cáncer de pulmón o no es significativa.

REALIZAR UNA COMPARACION ESTADÍSTICA DE LOS INDIVIDUOS CON/SIN CANCER DE PULMÓN

Primero vamos a realizar la comparación estadística de las variables categóricas.

# Seleccionar un subconjunto de variables del dataset original '1'
lF = LungC[ ,c(1:2, 4:16) ]
# Se excluye la columna 3 del dataset(posiblemente una variable no categórica o redundante)
# Se seleccionan las columnas 1 y 2(probablemente 'GENDER' y 'AGE') y de la 4 a la 16(todas las demás excepto la excluida)

# Crear una tabla interactiva con el dataset filtrado usando DT: :datatable()
DT::datatable(lF,
              rownames = TRUE, # Muestra los nombres de las filas
              options = list(pageLength = 10, # Establece el número de filas visibles por página
                              scrollX = TRUE),# Habilita la barra de desplazamiento horizontal si es necesaria
              class = "white-space: nowrap")# Evita que el texto se divida en varias lineas dentro de las celdas

Primero vamos a comprobar si hay variables que puedan covariar entre ellas mediante el coeficiente de Cramér generando una matriz que nos indique variable a variable como correlacionan.

# Crear una matriz vacía para almacenar los coeficientes de correlación de Cramér
m = matrix(ncol = length(lF), # Número de columnas igual al número de variables en lF
nrow =length(lF), # Numero de filas igual al número de variables en lF
dimnames = list(names(lF) , names(lF) ) ) # Asignar nombres de filas y columnas con los nombres de las variables

# Definir una función para calcular el coeficiente de Cramer entre todas las variables categoric

cramer = function(m, lF) {
  for(r in seq(nrow(m))) { # Iterar sobre las filas de la matriz
    for(c in seq(ncol(m))) { # Iterar sobre las columnas de la matriz
      m[[r,c]] = assocstats(table(lF[[r]], lF[[c]]))$cramer
      # Crear una tabla de contingencia entre dos variables y extraer el coeficiente de Cramér
    }
  }
  return(m) # Devolver la matriz con los coeficientes de Cramér
}
    

# Aplicar la función para calcular la matriz de correlación
cor = cramer(m, lF)

# Redondear los valores de la matriz a 3 decimales
cor_r = round(cor, 3)

# Convertir la matriz en un data frame y resaltar valores mayores a 0.3 en negrita
cor_m = cor_r %>%
  as.data.frame() %>%
  mutate_all(~ ifelse(. > 0.3,
                      cell_spec(., "html", bold = TRUE),
                      .))

cor_m %>%
  kable(escape = FALSE, format = "html") %>%
  add_header_above(c("Matriz de correlacion de variables factor" = 16),
                   color = "black", bold = TRUE, font_size = 18) %>%
  kable_styling("striped",
                full_width = FALSE,
                position = "center",
                font_size = 16,
                fixed_thead = TRUE) %>%  # Fija la cabecera
  column_spec(1, bold = TRUE) %>%
  row_spec(0, bold = TRUE, color = "orange") %>%
  scroll_box(width = "100%") # Removed height argument
Matriz de correlacion de variables factor
LUNG_CANCER GENDER SMOKING YELLOW_FINGERS ANXIETY PEER_PRESSURE CHRONIC_DISEASE FATIGUE ALLERGY WHEEZING ALCOHOL_CONSUMING COUGHING SHORTNESS_OF_BREATH SWALLOWING_DIFFICULTY CHEST_PAIN
LUNG_CANCER 1 0.067 0.058 0.181 0.145 0.186 0.111 0.151 0.328 0.249 0.289 0.249 0.061 0.26 0.19
GENDER 0.067 1 0.036 0.213 0.152 0.276 0.205 0.084 0.154 0.141 0.454 0.133 0.065 0.078 0.363
SMOKING 0.058 0.036 1 0.015 0.16 0.043 0.142 0.03 0.002 0.129 0.051 0.129 0.061 0.031 0.12
YELLOW_FINGERS 0.181 0.213 0.015 1 0.566 0.323 0.041 0.118 0.144 0.079 0.289 0.013 0.106 0.346 0.105
ANXIETY 0.145 0.152 0.16 0.566 1 0.217 0.01 0.189 0.166 0.192 0.166 0.226 0.144 0.489 0.114
PEER_PRESSURE 0.186 0.276 0.043 0.323 0.217 1 0.049 0.078 0.082 0.069 0.16 0.089 0.22 0.367 0.095
CHRONIC_DISEASE 0.111 0.205 0.142 0.041 0.01 0.049 1 0.111 0.106 0.05 0.002 0.175 0.026 0.075 0.037
FATIGUE 0.151 0.084 0.03 0.118 0.189 0.078 0.111 1 0.003 0.142 0.191 0.147 0.442 0.133 0.011
ALLERGY 0.328 0.154 0.002 0.144 0.166 0.082 0.106 0.003 1 0.174 0.344 0.19 0.03 0.062 0.239
WHEEZING 0.249 0.141 0.129 0.079 0.192 0.069 0.05 0.142 0.174 1 0.266 0.374 0.038 0.069 0.148
ALCOHOL_CONSUMING 0.289 0.454 0.051 0.289 0.166 0.16 0.002 0.191 0.344 0.266 1 0.203 0.179 0.009 0.331
COUGHING 0.249 0.133 0.129 0.013 0.226 0.089 0.175 0.147 0.19 0.374 0.203 1 0.277 0.158 0.084
SHORTNESS_OF_BREATH 0.061 0.065 0.061 0.106 0.144 0.22 0.026 0.442 0.03 0.038 0.179 0.277 1 0.161 0.024
SWALLOWING_DIFFICULTY 0.26 0.078 0.031 0.346 0.489 0.367 0.075 0.133 0.062 0.069 0.009 0.158 0.161 1 0.069
CHEST_PAIN 0.19 0.363 0.12 0.105 0.114 0.095 0.037 0.011 0.239 0.148 0.331 0.084 0.024 0.069 1


Las variables con mayor correlación serian:

PEER PRESURE con YELLOW FINGUERS
SWALLOWING_DIFFICULTY con ANXIETY
FATIGUE con SHORTNESS_OF_BREATH
ALCOHOL_CONSUMING con GENDER

Vamos a establecer el coeficiente de Cramér entre LUNG CANCER y el resto de variables. También vamos a realizar un test de chi-cuadrado para establecer si las diferencias entre LUNG CANCER y el resto de variables son significativamente diferentes o no y por tanto determinar si hay asociación o no.

# Crear una matriz vacía para almacenar los resultados del test de Chi-cuadrado y coeficiente de Cramér
m = matrix(nrow = 14, # 14 filas correspondientes a las variables categóricas analizadas
            ncol = 2, # 2 columnas: una para el p-valor del test de Chi-cuadrado y otra para el coeficiente de Cramer
            dimnames = list(colnames(LungC[, c(2, 4:16)]), # Nombres de filas: variables analizadas(excluyendo la respuesta)

c("p_valor", "Coeficiente_v_de_Cramer")))

# Iterar sobre las variables categóricas seleccionadas(excluyendo la respuesta)
for(i in c(2, 4:16)){
  tabla = table(LungC$LUNG_CANCER, LungC[[i]]) # Crear tabla de contingencia entre 'LUNG_CANCER' y la v ariable i
  test = chisq.test(tabla) # Aplicar test de Chi-cuadrado a la tabla
  
  # Definir función para calcular el coeficiente de Cramér
  cramer = function(x) {
    unname(sqrt(chisq.test(x) $statistic /(sum(x) *(min(dim(x))-1))))
  }
  
  # Guardar los valores en la matriz:
  # - p-valor del test de Chi-cuadrado
  # - coeficiente de Cramér(medida de asociación entre variables categóricas)
  m[colnames(LungC)[i],] = c(round(test$p.value, 4),
                             round(cramer(tabla), 4))
}

# Convertir la matriz en un data frame y resaltar valores significativos
m = as.data.frame(m) %>%
  mutate(
    p_valor = ifelse(as.numeric(p_valor) < 0.05,
                     cell_spec(p_valor, "html", bold = TRUE), # Resaltar p-valores < 0.05 en negrita
                     p_valor),
    Coeficiente_v_de_Cramer = ifelse(as.numeric(Coeficiente_v_de_Cramer) > 0.3,
                                     cell_spec(Coeficiente_v_de_Cramer, "html", bold = TRUE), #Resaltar coeficientes > 0.3 en negrita
                                     Coeficiente_v_de_Cramer)
  )

# Crear tabla bien formateada con los resultados
m %>%
  kable(escape = FALSE, format = "html") %>%
  add_header_above(c("p-valor test chi-cuadrado \nCoeficiente de Cramer de variables factor" = 3),
                    color = "black", bold = TRUE, font_size = 18) %>%
  kable_styling("striped",
                 full_width = FALSE,
                 position = "center",
                 font_size = 16) %>%
  column_spec(1, bold = TRUE) %>%
  row_spec(0, bold = TRUE, color = "orange")
p-valor test chi-cuadrado
Coeficiente de Cramer de variables factor
p_valor Coeficiente_v_de_Cramer
GENDER 0.3122 0.0575
SMOKING 0.3953 0.0484
YELLOW_FINGERS 0.0026 0.1715
ANXIETY 0.0175 0.1352
PEER_PRESSURE 0.0019 0.1766
CHRONIC_DISEASE 0.0754 0.1011
FATIGUE 0.0137 0.1403
ALLERGY 0 0.318
WHEEZING 0 0.2395
ALCOHOL_CONSUMING 0 0.2787
COUGHING 0 0.2387
SHORTNESS_OF_BREATH 0.3739 0.0506
SWALLOWING_DIFFICULTY 0 0.25
CHEST_PAIN 0.0015 0.1806

Con estos datos y estos resultados podemos decir que algunas variables, como GENDER, SMOKING, CHRONIC DISEASE y SHORTNESS_OF_BREATH no muestran diferencias significativas(p-valor > 0.05) con padecer o no cáncer de pulmón, lo que implica que, según esta base de datos, no están claramente asociadas con la enfermedad.

El resto de variables sí muestran diferencias significativas(p-valor < 0.05) con padecer o no cáncer de pulmón y una asociación moderada o fuerte con el cáncer de pulmón(en función del valor del coeficiente de Cramér). Estas pueden considerarse factores importantes asociados con el cáncer de pulmón en esta muestra.

Hay que tener en cuenta que la desproporción de pacientes con cáncer de pulmón(n= 270) y sin cáncer(n = 39) puede tener un gran impacto en el test de chi-cuadrado y el coeficiente de Cramér llevando a resultados que no son correctos en la realidad, por ejemplo, es ampliamente conocido y establecido que el cáncer de pulmón sí que esta asociado a ser fumador o no. Podríamos plantearnos ampliar la base de datos o utilizar el test exacto de Fischer para muestras pequeñas o des balanceadas.

Vamos a realizar un test no paramétrico, el test de Wilcoxon, para ver si la diferencia de edad(AGE) entre los pacientes con cáncer de pulmón o no(LUNG CANCER) es significativa o no.

# Crear una matriz vacia para almacenar el p-valor del test de Wilcoxon
mnum = matrix(nrow = 1, # Una sola fila ya que solo evaluamos la variable AGE
               ncol = 1, # Una sola columna para almacenar el p-valor
               dimnames = list(colnames(LungC[3]), # Nombre de la fila con la variable numerica "AGE"
                               c("p_valor") )) # Nombre de la columna

# Aplica[ el test de Wilcoxon para comparar la edad entre pacientes con y sin cáncer de pulmón
for(i in c(3)){ # Se selecciona la variable en la columna 3(AGE)
  f = formula(paste(colnames(LungC) [i], "~ LUNG_CANCER") ) # Construir la formula AGE ~ LUNG CANCER
  test = wilcox.test(f, data = LungC) # Realizar test de Wilcoxon para comparar medianas
  mnum [1,1] = c(round(test$p.value, 4)) # Guardar el p-valor del test en la matriz
}


# Convertir la matriz en un data frame para su visualización
mnum = as.data.frame(mnum) %>%
  mutate(p_valor = ifelse(as.numeric(p_valor) < 0.05,
                           cell_spec(p_valor, "html", bold = TRUE), # Resaltar valores significativos en negrita
                           p_valor) )

# Mostrar los resultados en una tabla bien formateada con kable()
mnum %>%
  kable(escape = FALSE, format = "html") %>%
  add_header_above(c("Test Wilcoxon de variables numericas" = 2),
                    color = "black", bold = TRUE, font_size = 18) %>%
  kable_styling("striped",
                 full_width = FALSE,
                 position = "center",
                 font_size = 16) %>%
  column_spec(1, bold = TRUE) %>%
  row_spec(0, bold = TRUE, color = "orange")
Test Wilcoxon de variables numericas
p_valor
AGE 0.1823

CREAR 1 MODELO PREDICTIVO DEL CÁNCER DE PULMON CON RANDOM FOREST

Vamos a crear un modelo predictivo, el Random Forest, con los datos que hemos ido trabajando y ver si somos capaces de predecir si un paciente tiene cáncer de pulmón o no. Se va utilizar la variable LUNG CANCER como variable que queremos predecir en función del resto. Se van a utilizar el 80% de los datos para entrenar el modelo y el 20% restante para testar el modelo teniendo en cuenta du se coge 1% de datos relativos a pacientes sin cáncer de pulmón. Los datos se van a normalizar y escalar(tanto los de entrenamiento como los datos que hemos reservado para testar el modelo entrenado).

# Inicializar un dataframe vació para almacenar los resultados del modelo Random Forest
df_results_rf = NULL

# Bucle para ejecutar el modelo 10 veces con diferentes semillas
for(i in 1:10){
  set.seed(i) # Establecer una semilla aleatoria para reproducibilidad
  
  # Dividir el conjunto de datos en entrenamiento(80%) y prueba(20%)
  train_row_numbers = createDataPartition(LungC$LUNG_CANCER, p = 0.8, list = FALSE)
  d_train = LungC[train_row_numbers, ] # Datos de entrenamiento
  d_test = LungC[-train_row_numbers, ] # Datos de prueba

  # Preprocesamiento de datos con 'recipes' para normalizar y transformar variables
  transformer = recipe(LUNG_CANCER ~ ., data = d_train) %>%
    step_dummy(all_nominal_predictors()) %>% # Convertir variables categóricas en dummies
    step_center(all_numeric_predictors()) %>% # Centrar variables numéricas
    step_scale(all_numeric_predictors()) # Escalar variables numéricas

  # Preparar el transformador con los datos de entrenamiento
  transformer_prepped = prep(transformer, training = d_train)
  
  # Aplicar las transformaciones al conjunto de entrenamiento y prueba
  data_train = bake(transformer_prepped, new_data = NULL)
  data_test = bake(transformer_prepped, new_data = d_test)

  # Configuración del control de entrenamiento para la validación cruzada de 10 pliegues
  ctrl = trainControl(
    method = "cv", # Validación cruzada
    number = 10, # Numero de pliegues
    returnResamp = "final", # Retornar resultados finales de la validación cruzada
    verboseIter = FALSE, # No mostrar detalles del entrenamiento
    summaryFunction = twoClassSummary, # Función de resumen para clasificación binaria
    classProbs = TRUE, # Habilitar probabilidades de clase
    savePredictions = TRUE, # Guardar predicciones
    allowParallel = TRUE, # Habilitar computación en paralelo
    sampling = "up" # Equilibrar clases en el conjunto de entrenamiento
    )

  # Definir una grilla de hiperparametros para ajustar 'mtry' en el Random Forest
  tuneGrid = expand.grid(mtry = 2:16)

  set.seed(i) # Fijar semilla para reproducibilidad

  # Entrenar el modelo Random Forest
  rf_fit = train(
    LUNG_CANCER ~ .,
    data = data_train, # Conjunto de entrenamients
    method = "rf", # Metodo de Random Forest
    metric = "ROC", # Utilizar la métrica AUC-ROC para optimización
    trControl = ctrl, # Control de validacion crazada
  )
  
  # Definir un rango de umbrales de probabilidad para evaluar el modelo
  probs = seq(0.1, 0.9, by = 0.1)

  set.seed(i) # Fijar semilla

  # Evaluar el rendimiento del modelo en diferentes umbrales
  ths_rf_fit = thresholder(
    rf_fit,
    threshold = probs, # Evaluar múltiples umbrales de decisión
    final = TRUE,
    statistics = "all"
  )
  
  # Seleccionar el umbral óptimo basado en el indice de Youden(J)
  best_thresh = ths_rf_fit %>%
    mutate(prob = probs) %>%
    filter(J == max(J) ) %>%
    pull(prob)

  # Si hay más de un umbral con la máxima métrica J, elegir el primero
  if(length(best_thresh) > 1) {
    thresh_prob_rf_fit = best_thresh [1]
    } 
  else {
      thresh_prob_rf_fit = best_thresh
    }

  # Generar predicciones con el modelo ajustado y el umbral seleccionado
  preds = as.factor(ifelse(predict(rf_fit, data_test, type = "prob") [ , "Si"] >= thresh_prob_rf_fit, "Si", "No"))

  # Obtener la variable real de prueba
  real = factor(d_test$LUNG_CANCER)
  
  # Verificar que la cantidad de predicciones y valores reales coincida
  if(length(preds) != length(real)){
    stop("Error: El numero de predicciones no coincide con el número de valores reales.")
  }
  
  # Crear matriz de confusión para evaluar el rendimiento del modelo
  cm = ConfusionTableR::binary_class_cm(
    preds,
    real,
    mode = 'everything',
    positive = 'Si'
  )
  
  # Extraer métricas de desempeño del modelo
  sensitivity = cm$confusion_matrix$byClass ['Sensitivity'] # Sensibilidad
  specificity = cm$confusion_matrix$byClass ['Specificity' ] # Especificidad

  # Convertir variables categóricas a numéricas para calcular el AUC
  df = data.frame(preds = preds, real = real)
  df$preds = as.numeric(ifelse(df$preds == "Si", 1, 0))
  df$real = as.numeric(ifelse(df$real == "Si", 1, 0))
  
  # Calcular el Área Bajo la Curva ROC(AUC)
  auc = roc(df$real, df$preds)$auc
  
  # Guardar los resultados de la iteración en un dataframe
  row = data.frame(
    model = "Random forest",
    seed = i,
    probab = thresh_prob_rf_fit,
    max_J_train = max(ths_rf_fit$J),
    sensitivity = sensitivity,
    specificity = specificity,
    AUC = auc
  )
  
  # Añadir los resultados de esta iteración al dataframe final
  df_results_rf = rbind(df_results_rf, row)
}
# Presentar los resultados en una tabla bien formateada
df_results_rf %>%
  kable() %>%
  add_header_above(c("Resultados modelo Random Forest" = 8),
                    color = "black", bold = TRUE, font_size = 18) %>%
  kable_styling("striped",
                full_width = FALSE,
                position = "center",
                font_size = 16) %>%
  row_spec(0, bold = TRUE, color = "orange")
Resultados modelo Random Forest
model seed probab max_J_train sensitivity specificity AUC
Sensitivity Random forest 1 0.2 0.7593074 0.9814815 0.1428571 0.5621693
Sensitivity1 Random forest 2 0.3 0.7841991 1.0000000 0.4285714 0.7142857
Sensitivity2 Random forest 3 0.4 0.7682900 0.9259259 0.5714286 0.7486772
Sensitivity3 Random forest 4 0.3 0.7971861 1.0000000 0.2857143 0.6428571
Sensitivity4 Random forest 5 0.3 0.7714286 0.9629630 0.5714286 0.7671958
Sensitivity5 Random forest 6 0.2 0.6686147 0.9444444 0.4285714 0.6865079
Sensitivity6 Random forest 7 0.1 0.7441558 0.9444444 0.0000000 0.4722222
Sensitivity7 Random forest 8 0.2 0.7580087 0.9444444 0.5714286 0.7579365
Sensitivity8 Random forest 9 0.3 0.7414502 1.0000000 0.8571429 0.9285714
Sensitivity9 Random forest 10 0.2 0.6846320 0.9629630 0.5714286 0.7671958

En esta tabla se muestran un total de 10 repeticiones del modelo de Random Forest. Podemos observar que los valores son similares pero no identicos ya que los datos al hacer el modelo se han ido cogido al azar y no de la misma manera pero sí similar.

Vamos a resumir los datos del modelo obtenido (sensibilidad, especificidad y AUC).

# Guardar Los resultados del modelo Random Forest en un archivo Excel
write.xlsx(df_results_rf, "lung_rf_MMG.xlsx")
# Combinar Los resultados [on un único dataframe (en este caso, solo contiene Random Forest)
df_results = rbind(df_results_rf)

# Guardar los resultados combinados en un archivo Csv
write.csv(df_results, "Resultado_Modelos_Lung_cancer_MMG.csv")
# Cargar Los resultados del modelo desde un archivo CSV
data = read.csv("Resultado_Modelos_Lung_cancer_MMG.csv")

# Asignar Los datos a un nuevo dataframe LLamado MRF
MRF = data
MRF["X"] = NULL # Se elimina La columna "X" si está presente (posiblemente un indice generado automáticamente).
MRF["seed"] = NULL # Se elimina La columna "seed", que indica la semilla utilizada en cada iteración del modelo.
MRF["max_J_train"] = NULL # Se elimina "max_J_train", que contiene el valor máximo del estadístico J durante el entrenamiento.
MRF["probab"] = NULL # Se elimina "probab", que indica el umbral de probabilidad usado en la clasificación


# Convertir la columna "model" en un factor para facilitar su análisis y visualización
MRF$model = as.factor(as.character(MRF$model))

# Definir el formato visual para la tabla
formato = c("striped", "bordered", "hover", "responsive")

# Crear y personalizar una tabla con Los resultados del modelo Random Forest
MRF %>%
  kable() %>%
  add_header_above(c("Resultados modelo Random Forest" = 4),
                   color = "black", bold = TRUE, font_size = 18) %>%
  kable_styling("striped",
                full_width = FALSE,
                position = "center",
                font_size = 16) %>%
  row_spec(0, bold = TRUE, color = "orange")
Resultados modelo Random Forest
model sensitivity specificity AUC
Random forest 0.9814815 0.1428571 0.5621693
Random forest 1.0000000 0.4285714 0.7142857
Random forest 0.9259259 0.5714286 0.7486772
Random forest 1.0000000 0.2857143 0.6428571
Random forest 0.9629630 0.5714286 0.7671958
Random forest 0.9444444 0.4285714 0.6865079
Random forest 0.9444444 0.0000000 0.4722222
Random forest 0.9444444 0.5714286 0.7579365
Random forest 1.0000000 0.8571429 0.9285714
Random forest 0.9629630 0.5714286 0.7671958

Realizaremos los boxplot de los tres parámetros (sensibilidad, especificidad y AUC) para tener una idea de como se distribuyen los resultados de las 10 repeticiones y vamos a calcular las medianas de los valores obtenidos para obtener los datos resumen de nuestro modelo.

# Crear un boxplot para visualizar la distribución de la sensibilidad del modeto Random Forest
BSS = ggplot(MRF, aes(x = model, y = sensitivity, fill = model)) +

# Agregar un gráfico de caja (boxplot) para mostrar la distribución de la sensibilidad
geom_boxplot() +

# Agregar una línea en la mediana de cada boxplot (color azul)
stat_summary(fun = median, geom = "crossbar", width = 0.75, color = "blue", size = 0.5) +

# Definir Los colores de relleno para los modetos
scale_fill_manual(values = c("Random forest" = "lightblue")) +

# Aplicar el tema gris a la gráfica
theme_grey() +
  # Personalizar el diseño del gráfico
  theme (
    panel.spacing = unit(1, "lines"), # Espaciado entre paneles
    axis.text.x = element_text(angle = 0, vjust = 0.5), # Ajustar la posición del texto en el eje X
    strip.text = element_text(size = 10), # Tamaño de texto de etiquetas
    plot.title = element_text(size = 18, hjust = 0.5) # Centrar el títuto del gráfico
    ) +
  
  # Etiquetas de La gráfica
  labs(
    title = "Boxplot de la sensibilidad \nen funcion del modelo Random Forest",
    x = "Modelo",
    y = "Sensibilidad",
    fill = "Modelo"
    )

# Convertir el gráfico en un gráfico interactivo con ggplotly
p_interactive = ggplotly(BSS, height = 600, width = 700)

# Personalizar la disposición del gráfico interactivo
p_interactive = p_interactive %>% layout(
  hoverlabel = list(
    bgcolor = "black", # Fondo negro en la etiqueta emergente
    font = list(color = "white") # Texto blanco en la etiqueta emergente
    ),
  margin = list(l = 100, r = 50, b = 100, t = 100), # Márgenes del gráfico
  xaxis = list(tickangle = 0), # Mantener etiquetas del eje X en horizontal
  yaxis = list(automargin = TRUE) # Ajustar el eje Y automáticamente
  )

# Mostrar el gráfico interactivo
p_interactive
# Calcular La mediana de la sensibilidad por cada modelo en
sensibilidad = tapply(MRF$sensitivity, MRF$model, median)

# Convertir el resultado en un data frame para facilitar su manipulación y visualización
sensibilidad = data.frame(sensibilidad)

# Renombrar La columna del data frame para una mejor identificación
names(sensibilidad) = c("Sensibilidad")
# Crear un boxplot para visualizar La especificidad de cada modelo en MRF
BSP = ggplot(MRF, aes(x = model, y = specificity, fill = model)) +
  geom_boxplot() + # Agregar boxplots para cada modelo
  stat_summary(fun = median, geom = "crossbar", width = 0.75, color = "blue", size = 0.5) + # Agregar línea de mediana en azul
  scale_fill_manual(values = c("Random forest" = "lightpink")) + # Definir colores personalizados
  theme_grey() + # Aplicar tema gris por defecto
  theme(
    panel.spacing = unit(1, "lines"), # Espaciado entre paneles
    axis.text.x = element_text(angle = 0, vjust = 0.5), # Ajuste del texto en el eje X
    strip.text = element_text(size = 10), # Tamaño de texto en etiquetas de facetas
    plot.title = element_text(size = 18, hjust = 0.5) # Tamaño y alineación del título
    ) +
  labs(title = "Boxplot de la especificidad \nen funcion del modelo Random Forest",
       x = "Modelo",
       y = "Especificidad",
       fill = "Modelo") # Etiquetas del gráfico

# Convertir el gráfico en una versión interactiva con plotly
p_interactive = ggplotly(BSP, height = 600, width = 700)

# Ajustar la apariencia de la etiqueta emergente y márgenes del gráfico interactivo
p_interactive = p_interactive %>% layout(
  hoverlabel = list(
    bgcolor = "black", # Fondo negro para la etiqueta emergente
    font = list(color = "white") # Texto blanco en la etiqueta emergente
    ),
  margin = list(l = 100, r = 50, b = 100, t = 100), # Ajuste de márgenes
  xaxis = list(tickangle = 0),
  yaxis = list(automargin = TRUE)
)

# Mostrar el gráfico interactivo
p_interactive
# Calcular La mediana de la sensibilidad por cada modelo en
especificidad = tapply(MRF$specificity, MRF$model, median)

# Convertir el resultado en un data frame para facilitar su manipulación y visualización
especificidad = data.frame(especificidad)

# Renombrar La columna del data frame para una mejor identificación
names(especificidad) = c("Especificidad")
# Crear un boxplot para visualizar el AUC (Área Bajo la Curva) por modelo
BAUC = ggplot(MRF, aes(x = model, y = AUC, fill = model)) +
  geom_boxplot() + # Agregar boxplots
  stat_summary(fun = median, geom = "crossbar", width = 0.75, color = "blue", size = 0.5) + # Mediana en azul
  scale_fill_manual(values = c("Random forest" = "lightgreen")) + # Color verde para Los modelos Random Forest
  theme_grey() + # Aplicar tema gris estándar
  theme(
    panel.spacing = unit(1, "lines"),
    axis.text.x = element_text(angle = 0, vjust = 0.5),
    strip.text = element_text(size = 10),
    plot.title = element_text(size = 18, hjust = 0.5)
    ) +
  labs(title = "Boxplot de AUC \nen funcion del modelo Random Forest",
       x = "Modelo",
       y = "AUC",
       fill = "Modelo") # Etiquetas del gráfico

# Convertir en gráfico interactivo con plotly
p_interactive = ggplotly(BAUC, height = 500, width = 700)

# Ajustar la apariencia de la etiqueta emergente y márgenes
p_interactive = p_interactive %>% layout(
  hoverlabel = list(
    bgcolor = "black", # Fondo negro en Las etiquetas emergentes
    font = list(color = "white") # Texto blanco
    ),
  margin = list(l = 100, r = 50, b = 100, t = 100),
  xaxis = list(tickangle = 0),
  yaxis = list(automargin = TRUE)
  )

# Mostrar el gráfico interactivo
p_interactive
# Calcular La mediana del AUC (Área Bajo La Curva) para cada modelo en MRF
auc = tapply(MRF$AUC, MRF$model, median)

# Convertir el resultado en un data frame para su posterior visualización y manipulación
auc = data.frame(auc)

# Renombrar la columna del data frame a "AUC" para mayor claridad
names(auc) = c("AUC")
# Combinar Los resultados de sensibilidad, especificidad y AUC en un solo data frame
final = cbind(sensibilidad, especificidad, auc)

# Convertir la variable 'model' en un factor para facilitar su interpretación en el analisis
MRF$model = as.factor(as.character(MRF$model))

# Definir el formato de la tabla
formato = c("striped", "bordered", "hover", "responsive")

# Crear la tabla con los resultados finales usando kable para mejorar su presentación
final %>%
  kable() %>% # Convertir el data frame en tabla
  add_header_above(c("Resultados Final modelo Random Forest" = 4), color = "black", bold = TRUE, font_size = 18) %>%
  kable_styling("striped", # Aplicar estilo de tabla con líneas intercaladas
                full_width = FALSE, # Ajustar la tabla al contenido
                position = "center", # Centrar la tabla
                font_size = 16) %>%
  row_spec(0, bold = TRUE, color = "orange") # Resaltar la primera fila en negrita con color naranja
Resultados Final modelo Random Forest
Sensibilidad Especificidad AUC
Random forest 0.962963 0.5 0.7314815

De manera final, nuestro modelo realizado en Random Forest, vemos que de mediana tiene una sensibilidad de 0.963, una especificidad de 0.5 y una área bajo la curva (AUC) de 0.731. Con los datos obtenidos en general podemos decir que el modelo es muy efectivo para detectar los casos positivos (alta sensibilidad) pero no lo es tanto para clasificar los negativos pudiendo generar mucho falsos positivos (especificidad regular). Cabe decir que en los datos que nos concierne, detectar los positivos es altamente más crucial o importante que generar algún falso positivo. El AUC obtenido sugiere un rendimiento moderado aceptable pero con margen de mejora.