Preliminares

El aprendizaje supervisado es una técnica usada en minería de datos, en la que se genera una función de pronóstico a partir del entrenamiento previo sobre datos etiquetados. Es decir, aprendemos a partir de casos reales y extrapolamos el resultado a los casos futuros.

El proceso habitual consiste en dividir la muestra en dos conjuntos, uno de entrenamiento y otro de prueba. Los datos de entrenamiento son utilizados para ajustar un modelo de predicción y los datos de prueba se emplean para comprobar el comportamiento del modelo estimado. Estos dos conjuntos son disjuntos y existen diferentes formas para escogerlos.

Los modelos de aprendizaje supervisado, se denominan habitualmente modelos de clasificación ya que su objetivo es agrupar en conjuntos con características semejantes, y la variable respuesta es el grupo al que pertenece cada elemento.

Cuando se aplica cualquier método de clasificación, se pueden cometer dos errores, en el caso de una variable binaria que toma valores, por ejemplo, -1 y 1, donde en la literatura hablamos de positivos y negativos, habrán negativos que se clasifiquen incorrectamente como positivos y positivos que se clasifiquen incorrectamente como negativos. A partir de este recuento se puede construir el siguiente cuadro de clasificación:

Valor estimado \((\widehat{Y}_i)\) \(\backslash\) Valor real \((Y_i)\) \(Y_i=-1\) \(Y_i=1\)
\(\widehat{Y}_i=-1\) \(TN\) \(FN\)
\(\widehat{Y}_i=1\) \(FP\) \(TP\)

Donde \(TN\) y \(TP\) corresponderán a predicciones correctas, mientras que \(FN\) y \(FP\) corresponderán a predicciones erróneas. A partir de estos valores se pueden definir los suigientes índices:

Índice Definición Expresión
Tasa de aciertos Cociente entre las predicciones correctas y el total de predicciones \(\dfrac{TN+TP}{TN +FN +FP +TP}\)
Tasa de errores Cociente entre las predicciones incorrectas y el total de predicciones \(\dfrac{FN +FP}{TN +FN +FP +TP}\)
Especificidad Proporción entre la frecuencia valores negativos correctos y el total de valores negativos \(\dfrac{TN}{FP+TN}\)
Sensibilidad Proporción entre la frecuencia de valores positivos correctos y el total de valores positivos \(\dfrac{TP}{FN+TP}\)

Curva ROC

Un método para evaluar clasificadores alternativo a la métrica expuesta es la curva ROC (Receiver Operating Characteristic). La curva ROC es una representación gráfica del rendimiento del clasificador que muestra la distribución de las fracciones de verdaderos positivos y de falsos positivos. La fracción de verdaderos positivos se conoce como sensibilidad, sería la probabilidad de clasificar correctamente a un individuo cuyo estado real sea definido como positivo. La especificidad es la probabilidad de clasificar correctamente a un individuo cuyo estado real sea clasificado como negativo.

La curva ROC también es conocida como la representación de sensibilidad frente a (1-especificidad). Cada resultado de predicción representa un punto en el espacio ROC. El mejor método posible de predicción se situaría en un punto en la esquina superior izquierda, o coordenada \((0,1)\) del espacio ROC, representando un 100% de sensibilidad (ningún falso negativo) y un 100% también de especificidad (ningún falso positivo). Una clasificación totalmente aleatoria daría un punto a lo largo de la línea diagonal, que se llama también línea de no-discriminación, es decir, un modelo inútil. Por lo tanto, lo que se espera encontrar son puntos sobre una curva por encima de la diagonal y entre más cercana se encuentre de la esquina superior izquierda, mejor será su predicción.La curva ROC permite comparar modelos a través del área bajo su curva.

En la figura relizada de ejemplo, vemos de color rojo, la curva de una clasificación totalmente aleatoria, de color azul y purpura dos clasificaciones, donde claramente la clasificación por el método de color purpura es mejor.

Curva ROC en R

Para ver una aplicación sencilla de las curvas ROC, supongamos que tenemos una serie de pacientes sobre los que se mide la cantidad de glucosa en la sangre. Veremos si esa medida es una prueba apropiada para diagnosticar la diabetes. En el caso de que la prueba sea adecuada, deberíamos poder determinar también, cuál sería el punto de corte óptimo, es decir, cuál sería el nivel de glucosa en sangre para el que determinamos si un paciente es o no diabético.

Hay varios paquetes en R para calcular y dibujar las curvas ROC, vamos a ver dos de ellos y posteriormente veremos cómo se construye una curva ROC manualmente para comprender mejor su funcionamiento.

Paquete ROCR

Generemos a continuación un conjunto aleatorio de 100 pacientes diabéticos y otro de 100 pacientes sanos.

set.seed(2020)
enfms <- rnorm(100,173,2)
sanos <- rnorm(100,167,2)
datos <- data.frame(c(enfms,sanos),
                     as.factor(rep(c("Sanos","Enfermos"), times = 1, each = 100)))
colnames(datos) <- c("Valor","Clase")
denEnf <- density(enfms)
denSan <- density(sanos)
plot(NULL,xlim=c(160,185),ylim=c(0,0.25), type="n",
     xlab="Cantidad de glucosa en la sangre",ylab="Densidades")

lines(denEnf,col="red")
lines(denSan,col="blue")
text(164,0.25, "Sanos")
text(176,0.25, "Enfermos")

Como podemos ver en el gráfico de las curvas de densidad generadas a partir de los datos, la distribución de sanos solapa con la de enfermos. Es precisamente debido a ese solapamiento por lo que se hace necesario recurrir a algún tipo de herramienta predictiva que ayude a decidir sobre los casos dudosos.

La curva ROC que se genera tiene los siguientes elementos:

  • Eje de abscisas (\(x\)): Tasa de falsos positivos o (1−especificidad).

  • Eje de ordenadas (\(y\)): Tasa de verdaderos positivos o sensibilidad

  • Diagonal del gráfico: Divide la cuadrícula en dos mitades. Indica la clasificación de forma aleatoria.

  • Área bajo la curva (AUC): Aunque no es un elemento gráfico, es importante ya que indica cuánta área de la cuadrícula queda bajo la curva ROC.

  • El punto de color rojo: Indica el punto de corte óptimo (valor óptimo de corte) entre los grupos sanos y enfermos.

library(ROCR)
## Warning: package 'ROCR' was built under R version 3.6.3
## Loading required package: gplots
## 
## Attaching package: 'gplots'
## The following object is masked from 'package:stats':
## 
##     lowess
pred <- prediction(datos$Valor, datos$Clase)
perf <- performance(pred,measure="tpr",x.measure="fpr")

plot(perf,colorize=TRUE,type="l") 
abline(a=0,b=1)

# Área bajo la curva
AUC       <- performance(pred,measure="auc")
AUCaltura <- AUC@y.values

# Punto de corte óptimo
cost.perf <- performance(pred, measure ="cost")
opt.cut   <- pred@cutoffs[[1]][which.min(cost.perf@y.values[[1]])]
#coordenadas del punto de corte óptimo
x<-perf@x.values[[1]][which.min(cost.perf@y.values[[1]])]
y<-perf@y.values[[1]][which.min(cost.perf@y.values[[1]])]
points(x,y, pch=20, col="red")

cat("AUC:", AUCaltura[[1]]) 
## AUC: 0.9769
cat("Punto de corte óptimo:",opt.cut)
## Punto de corte óptimo: 170.6398

Paquete pROC

Continuando con el mismo ejemplo.

library(pROC)
## Warning: package 'pROC' was built under R version 3.6.3
## Type 'citation("pROC")' for a citation.
## 
## Attaching package: 'pROC'
## The following objects are masked from 'package:stats':
## 
##     cov, smooth, var
objroc <- roc(datos$Clase, datos$Valor,auc=T,ci=T)
## Setting levels: control = Enfermos, case = Sanos
## Setting direction: controls < cases
objroc
## 
## Call:
## roc.default(response = datos$Clase, predictor = datos$Valor,     auc = T, ci = T)
## 
## Data: datos$Valor in 100 controls (datos$Clase Enfermos) < 100 cases (datos$Clase Sanos).
## Area under the curve: 0.9769
## 95% CI: 0.9602-0.9936 (DeLong)
plot.roc(objroc,print.auc=T,print.thres = "best",
          col="blue",xlab="1-ESpecificidad",ylab="Sensibilidad")

Tanto el paquete ROCR como el paquete pROC nos dan de forma más o menos directa el punto de corte óptimo, pero también lo podríamos calcular nosotros mismos. Para ello existes varios métodos. Si lo que queremos es maximizar sensibilidad y especificidad se puede utilizar el índice de Youden, donde para cada par sensibilidad-especificidad, el punto de corte sería aquel donde se cumpla:

Índice de Youden \[\max(sensibilidad+especificidad−1)\] Con los datos de nuestro ejemplo, sería:

SensEspec <-objroc$sensitivities + objroc$specificities 
maximo    <- max(SensEspec)
numOrdenCutoff <- which(SensEspec==maximo)
objroc$thresholds[numOrdenCutoff]
## [1] 170.6046

El punto de corte óptimo es aquel que maximiza el cociente de verdaderos positivos (sensibilidad), al mismo tiempo minimiza el ratio de falsos positivos (1−especificidad). Desde una perspectiva gráfica y poco rigurosa, será el punto de la curva que quede lo más arriba y a la izquierda posible. Es llegar a un compromiso de maximización de ambos parámetros, teniendo en cuenta que aumentar uno significa disminuir el otro.

Habiamos comentado que es importante el valor del área que queda bajo la curva ROC (AUC). Este valor puede interpretarse como la probabilidad de que ante dos individuos, uno sano y otro enfermo, la prueba clasifique a los dos correctamente. Por lo tanto, cuanto mayor sea el valor del AUC mejor será la prueba diagnóstica. Un valor cercano al 0.5 (50$% del área total) será un valor bastante malo. dependiente del problema de investigación, se podróa ser más o menos exigente con el clasificador.

Una vez visto cómo generar con R una curva ROC, cómo interpretarla y cómo extraer los resultados de interés, podemos entrar en el “cómo se hace” de una curva ROC. Aunque ya se puede intuir cómo están construidas, vamos a verlo paso a paso, con su significado.

#Para los enfermos
muestra1 <- which(denEnf$y>0.005)
muestra1 <- sample(muestra1,75,replace=F)
y1 <- vector()
for(i in muestra1){
  y1 <- append(y1,runif(1,min(denEnf$y),denEnf$y[i])) 
}
#Para los sanos
muestra2 <- which(denSan$y>0.005)
muestra2 <- sample(muestra2,75,replace=F)
y2 <- vector()
for(i in muestra2){
  y2 <- append(y2,runif(1,min(denSan$y),denSan$y[i]))
}
incr <- 0
intersX <- which(diff(denEnf$y<denSan$y)!=0)

curvas <- function() {
plot(denEnf$x,denEnf$y,type = "l",
    xlim =c(min(min(denEnf$x ),min(denSan$x)),max(max(denEnf$x),max(denSan$x))),ylim=c(0,0.25)) 
lines(denSan$x,denSan$y)
points(denEnf$x[muestra1], y1, pch = "+",col="red")
text(175,0.25,labels = "Enfermos" )
points(denSan$x[muestra2], y2, pch = "*",col="blue")
text(165,0.25,labels = "Sanos" )
text(c(169,167,174,172),c(0,0.10,0.10,0), labels = c("FN","TN","TP","FP"))}

curvas()
abline(v=170.2,col="green") 

# número de FN
FN <- length(which(denEnf$x[muestra1] < denEnf$x[intersX]))
## Warning in denEnf$x[muestra1] < denEnf$x[intersX]: longitud de objeto mayor no
## es múltiplo de la longitud de uno menor
# Número de TP
TP <- length(which(denEnf$x[muestra1] >= denEnf$x[intersX]))
## Warning in denEnf$x[muestra1] >= denEnf$x[intersX]: longitud de objeto mayor no
## es múltiplo de la longitud de uno menor
# Número de FP
FP <- length(which(denSan$x[muestra2] >= denSan$x[intersX]))
## Warning in denSan$x[muestra2] >= denSan$x[intersX]: longitud de objeto mayor no
## es múltiplo de la longitud de uno menor
# Número de TN
TN <- length (which(denSan$x[muestra2] < denSan$x[intersX]))
## Warning in denSan$x[muestra2] < denSan$x[intersX]: longitud de objeto mayor no
## es múltiplo de la longitud de uno menor
(Sensibilidad  <- TP/(FN+TP))
## [1] 0.32
(Especificidad <- TN/(FP+TN))
## [1] 0.7066667

Tipos de errores

Nota importante: En la mayoría de investigaciones estadísticas es más grave cometer un error de tipo I, aunque en la la medicina pueden existir excepciones, generalmente será más grave no diagnosticar a un enfermo como tal que hacerlo a una persona sana.

Ejercicio

  • En el repositorio de datos ubicado en http://gauss.inf.um.es/datos/ la base de datos IMC.dat contiene el índice de masa corporal \((IMC)\,\, kg/m^2\) de 200 individuos y su clasiticación, sobrepeso (T) o sin sobrepeso (F).

  • En la base de datos peso.dat del mismo repositorio se encuentra el peso de 200 individuos igualmente clasificados con sobrepeso y sin él.

  • Se quiere determinar cuál de las 2 “pruebas diagnósticas” sería la más adecuada para determinar si un individuo tiene sobrepeso y cuál sería el punto de corte óptimo.

  • Con base en lo aprendido sobre curvas ROC, concluya sobre la situación.