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"
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
| 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
| 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.
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.
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
| 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 | 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")
| p_valor | |
|---|---|
| AGE | 0.1823 |
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")
| 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")
| 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
| 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.