Minería de datos - Aprendizaje Supervizado
Introducción.-
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:
Donde TN y TP corresponderán a preddiones correctas, mientras que FN y FP corresponderán a predicciones erroneas. A partir de estos valores se pueden definir los siguientes indices:
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 sensibilid
ad, 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.
ad, 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.
Curva ROC en python:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import roc_curve, auc
from sklearn.preprocessing import StandardScaler
# Generar datos ficticios
np.random.seed(0)
X = np.random.randn(100, 2)
y = np.random.randint(0, 2, 100)
# Dividir en conjuntos de entrenamiento y prueba
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# Estandarizar las características
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# Entrenar un clasificador SVM
svm = SVC(kernel='linear', probability=True)
svm.fit(X_train, y_train)
# Predecir probabilidades (necesarias para la curva ROC)
y_scores = svm.predict_proba(X_test)[:, 1]
# Calcular la curva ROC y el área bajo la curva (AUC)
fpr, tpr, thresholds = roc_curve(y_test, y_scores)
roc_auc = auc(fpr, tpr)
# Graficar la curva ROC
plt.figure(figsize=(8, 6))
plt.plot(fpr, tpr, color='darkorange', lw=2, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Curva ROC del clasificador SVM')
plt.legend(loc="lower right")
plt.show()
Ejemplo práctico.-
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.
En python se tiene:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# Fijar la semilla para la reproducibilidad
np.random.seed(2020)
# Generar datos normalmente distribuidos para enfermos y sanos
enfms = np.random.normal(173, 2, 100)
sanos = np.random.normal(167, 2, 100)
# Crear un DataFrame con los datos
datos = pd.DataFrame({
'Valor': np.concatenate([enfms, sanos]),
'Clase': ['Enfermos'] * 100 + ['Sanos'] * 100
})
# Crear gráficos de densidad
plt.figure(figsize=(10, 6))
sns.kdeplot(datos[datos['Clase'] == 'Enfermos']['Valor'], color='red', label='Enfermos')
sns.kdeplot(datos[datos['Clase'] == 'Sanos']['Valor'], color='blue', label='Sanos')
plt.xlim(160, 185)
plt.ylim(0, 0.25)
plt.xlabel('Cantidad de glucosa en la sangre')
plt.ylabel('Densidad')
plt.title('Densidades de Glucosa en Sangre para Sanos y Enfermos')
plt.legend()
plt.show()
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.
Codigo Python:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_curve, auc
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# Fijar la semilla para la reproducibilidad
np.random.seed(2020)
# Generar datos
enfms = np.random.normal(173, 2, 100)
sanos = np.random.normal(167, 2, 100)
# Crear un DataFrame
datos = pd.DataFrame({
'Valor': np.concatenate([enfms, sanos]),
'Clase': [1] * 100 + [0] * 100 # 1 para enfermos, 0 para sanos
})
# Dividir en entrenamiento y prueba
X = datos[['Valor']]
y = datos['Clase']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# Estandarizar los datos
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# Crear y entrenar el modelo de regresión logística
model = LogisticRegression()
model.fit(X_train, y_train)
# Calcular puntuaciones de predicción
y_scores = model.predict_proba(X_test)[:, 1]
# Calcular la curva ROC y el AUC
fpr, tpr, _ = roc_curve(y_test, y_scores)
roc_auc = auc(fpr, tpr)
# Graficar la curva ROC
plt.figure(figsize=(8, 6))
plt.plot(fpr, tpr, color='darkorange', lw=2, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Curva ROC')
plt.legend(loc="lower right")
plt.show()
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.
Análisis exploratorio de datos.-
El código es el siguiente:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# Fijar la semilla para la reproducibilidad
np.random.seed(2020)
# Generar datos
enfms = np.random.normal(173, 2, 100)
sanos = np.random.normal(167, 2, 100)
# Crear un DataFrame
datos = pd.DataFrame({
'Valor': np.concatenate([enfms, sanos]),
'Clase': ['Enfermos'] * 100 + ['Sanos'] * 100
})
# Resumen estadístico
print("Resumen estadístico:")
print(datos.describe())
# Histograma de las distribuciones
plt.figure(figsize=(10, 6))
sns.histplot(data=datos, x='Valor', hue='Clase', kde=True, element='step')
plt.title('Histograma de Valores para Sanos y Enfermos')
plt.xlabel('Valor')
plt.ylabel('Frecuencia')
plt.show()
# Boxplot para comparar distribuciones
plt.figure(figsize=(8, 6))
sns.boxplot(x='Clase', y='Valor', data=datos)
plt.title('Boxplot de Valores para Sanos y Enfermos')
plt.xlabel('Clase')
plt.ylabel('Valor')
plt.show()
# Densidad de cada grupo
plt.figure(figsize=(10, 6))
sns.kdeplot(datos[datos['Clase'] == 'Enfermos']['Valor'], color='red', label='Enfermos', shade=True)
sns.kdeplot(datos[datos['Clase'] == 'Sanos']['Valor'], color='blue', label='Sanos', shade=True)
plt.title('Densidad de Glucosa en Sangre para Sanos y Enfermos')
plt.xlabel('Cantidad de glucosa en la sangre')
plt.ylabel('Densidad')
plt.legend()
plt.show()
Conclusiones.-
La curva ROC ilustra la capacidad del clasificador para discriminar entre las dos clases (enfermos y sanos). Un área bajo la curva (AUC) cercana a 1 indica una excelente capacidad de discriminación, mientras que un AUC cercano a 0.5 sugiere que el modelo no es mejor que un lanzamiento aleatorio.
Equilibrio entre Sensibilidad y Especificidad:
La curva ROC proporciona una visualización del compromiso entre la sensibilidad (tasa de verdaderos positivos) y la especificidad (1 - tasa de falsos positivos) del modelo. En el contexto de diagnóstico médico, por ejemplo, la sensibilidad se refiere a la capacidad del modelo para identificar correctamente a los enfermos, mientras que la especificidad se refiere a su capacidad para identificar a los sanos.
Selección del Umbral de Decisión:
La curva ROC también ayuda en la selección de un umbral de decisión óptimo. Dependiendo de la importancia relativa de los falsos positivos frente a los falsos negativos (por ejemplo, en un contexto médico donde los falsos negativos pueden ser más críticos), se puede elegir un umbral que equilibre estos factores.
Comparación de Modelos:
Si se dispusiera de varios modelos, la curva ROC serviría para comparar su rendimiento. Un modelo con un área bajo la curva mayor sería generalmente preferible.
Limitaciones del Modelo en Datos Superpuestos:
Dado que los datos de "enfermos" y "sanos" tienen cierto grado de superposición, como se vio en los análisis anteriores, esto podría reflejarse en una curva ROC que no alcanza valores muy altos de AUC, lo que indica limitaciones en la capacidad del modelo para distinguir claramente entre las dos clases.
Importancia del Contexto de los Datos:
La interpretación de la curva ROC debe hacerse siempre considerando el contexto de los datos. En escenarios donde el costo de los falsos positivos y falsos negativos es significativo, como en el diagnóstico médico, estas consideraciones son especialmente importantes.
Bibliografía.-
"The Elements of Statistical Learning" por Trevor Hastie, Robert Tibshirani y Jerome Friedman
"Pattern Recognition and Machine Learning" por Christopher M. Bishop








Comentarios
Publicar un comentario