Métricas de Evaluación en Machine Learning

Las métricas de evaluación son herramientas fundamentales para medir el rendimiento de los modelos de clasificación en machine learning. Estas métricas nos permiten entender qué tan bien está funcionando nuestro modelo y dónde puede estar fallando, especialmente cuando trabajamos con diferentes tipos de datasets.

Matriz de Confusión: La Base de Todas las Métricas

La matriz de confusión es una tabla que descompone las predicciones del modelo comparándolas con los valores reales. Esta matriz es la base fundamental para calcular todas las demás métricas de evaluación.

Matriz de Confusión - Ejemplo Dataset Balanceado

Matriz de Confusión - Ejemplo Dataset Balanceado

Componentes de la Matriz de Confusión

La matriz de confusión se compone de cuatro elementos esenciales:

  • True Positives (TP): Predicciones correctas de la clase positiva - casos donde el modelo predijo correctamente que el resultado era positivo
  • True Negatives (TN): Predicciones correctas de la clase negativa - casos donde el modelo predijo correctamente que el resultado era negativo
  • False Positives (FP): Predicciones incorrectas como positivas - casos donde el modelo predijo positivo pero el resultado real era negativo (Error Tipo I)
  • False Negatives (FN): Predicciones incorrectas como negativas - casos donde el modelo predijo negativo pero el resultado real era positivo (Error Tipo II)

Métricas Principales Derivadas de la Matriz de Confusión

Accuracy (Exactitud)

La accuracy mide el porcentaje total de predicciones correctas:

Accuracy=TP+TNTP+TN+FP+FNAccuracy = \frac{TP + TN}{TP + TN + FP + FN}

Ejemplo de código:

from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y_true, y_pred)
# O calculada manualmente:
accuracy = (tp + tn) / (tp + tn + fp + fn)

Precision (Precisión)

La precision mide qué proporción de las predicciones positivas fueron correctas:

Precision=TPTP+FPPrecision = \frac{TP}{TP + FP}

La precision responde a la pregunta: “De todos los casos que predije como positivos, ¿cuántos realmente lo eran?”

Ejemplo de código:

from sklearn.metrics import precision_score
precision = precision_score(y_true, y_pred)
# O calculada manualmente:
precision = tp / (tp + fp)

Recall (Sensibilidad)

El recall mide qué proporción de los casos positivos reales fueron correctamente identificados:

Recall=TPTP+FNRecall = \frac{TP}{TP + FN}

También conocido como sensibilidad o True Positive Rate (TPR), responde: “De todos los casos positivos reales, ¿cuántos logré identificar?”

Ejemplo de código:

from sklearn.metrics import recall_score
recall = recall_score(y_true, y_pred)
# O calculada manualmente:
recall = tp / (tp + fn)

F1-Score

El F1-Score es la media armónica entre precision y recall:

F1Score=2×Precision×RecallPrecision+RecallF1-Score = 2 \times \frac{Precision \times Recall}{Precision + Recall}

Esta métrica es especialmente útil cuando necesitamos un equilibrio entre precision y recall:

Ejemplo de código:

from sklearn.metrics import f1_score
f1 = f1_score(y_true, y_pred)
# O calculada manualmente:
f1 = 2 * (precision * recall) / (precision + recall)

Specificity (Especificidad)

La specificity mide qué proporción de los casos negativos reales fueron correctamente identificados:

Specificity=TNTN+FPSpecificity = \frac{TN}{TN + FP}

También se conoce como True Negative Rate, y responde: “De todos los casos negativos reales, ¿cuántos identifiqué correctamente?”

Ejemplo de código:

# La especificidad no está en sklearn, hay que calcularla manualmente
specificity = tn / (tn + fp)

ROC-AUC: Evaluación Integral del Rendimiento

Curva ROC

La Receiver Operating Characteristic (ROC) es una curva que grafica la True Positive Rate (Sensibilidad) contra la False Positive Rate (1-Especificidad) en diferentes valores de threshold:

  • True Positive Rate (TPR) = Recall = Sensibilidad
  • False Positive Rate (FPR) = 1 - Especificidad = FPFP+TN\frac{FP}{FP + TN}

Area Under the Curve (AUC)

El AUC-ROC mide el área bajo la curva ROC. Esta métrica proporciona un valor único entre 0 y 1:

  • AUC = 1.0: Clasificación perfecta
  • AUC = 0.5: Rendimiento equivalente a adivinanza aleatoria
  • AUC < 0.5: Peor que adivinanza aleatoria

Comparación Curvas ROC - Dataset Balanceado vs Desbalanceado

Comparación Curvas ROC - Dataset Balanceado vs Desbalanceado

Ejemplo de código:

from sklearn.metrics import roc_curve, auc
import matplotlib.pyplot as plt

# Calcular curva ROC
fpr, tpr, thresholds = roc_curve(y_test, y_pred_proba)
roc_auc = auc(fpr, tpr)

# Graficar
plt.plot(fpr, tpr, label=f'ROC Curve (AUC = {roc_auc:.2f})')
plt.plot([0, 1], [0, 1], 'k--')  # Línea diagonal
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend()

El Problema de las Clases Desbalanceadas

Por qué Accuracy puede ser Engañosa

En datasets con clases desbalanceadas, la accuracy puede proporcionar una falsa sensación de buen rendimiento. Esto ocurre porque un modelo puede lograr alta accuracy simplemente prediciendo siempre la clase mayoritaria.

Ejemplo:

  • Dataset con 90% clase negativa, 10% clase positiva
  • Modelo que siempre predice “negativo”: 90% de accuracy
  • ¡Pero 0% de recall para la clase positiva!

Este fenómeno se conoce como la “paradoja de la accuracy”:

Métricas Alternativas para Datasets Desbalanceados

Para datasets desbalanceados, es preferible usar:

  1. Precision, Recall y F1-Score por clase individual
  2. Balanced Accuracy: Sensitivity+Specificity2\frac{Sensitivity + Specificity}{2}
  3. AUC-ROC: Menos sensible al desbalance de clases
  4. Cohen’s Kappa: Considera la concordancia esperada por azar

Ejemplo de código:

from sklearn.metrics import balanced_accuracy_score, cohen_kappa_score

balanced_acc = balanced_accuracy_score(y_true, y_pred)
kappa = cohen_kappa_score(y_true, y_pred)
macro_f1 = f1_score(y_true, y_pred, average='macro')
weighted_f1 = f1_score(y_true, y_pred, average='weighted')

Ajuste de Thresholds: Optimizando Métricas Específicas

¿Por qué Ajustar Thresholds?

La mayoría de los modelos de clasificación producen probabilidades, no decisiones binarias directas. El threshold (punto de corte) determina cuándo una probabilidad se convierte en una predicción de clase positiva.

Por defecto se usa threshold = 0.5, pero esto no siempre es óptimo.

Optimización de Threshold - Efecto en Métricas de Evaluación

Optimización de Threshold - Efecto en Métricas de Evaluación

Proceso de Optimización de Threshold

El proceso sistemático para encontrar el threshold óptimo:

  1. Entrenar el modelo en el conjunto de entrenamiento
  2. Obtener probabilidades en el conjunto de prueba
  3. Probar diferentes thresholds (ej: 0.1, 0.2, …, 0.9)
  4. Evaluar métricas para cada threshold
  5. Seleccionar el threshold que optimiza la métrica objetivo

Ejemplo de código:

def find_optimal_threshold(y_true, y_pred_proba, metric='f1'):
    thresholds = np.arange(0.01, 1.0, 0.01)
    best_score = 0
    best_threshold = 0.5
    
    for threshold in thresholds:
        y_pred = (y_pred_proba >= threshold).astype(int)
        
        if metric == 'f1':
            score = f1_score(y_true, y_pred, zero_division=0)
        elif metric == 'precision':
            score = precision_score(y_true, y_pred, zero_division=0)
        elif metric == 'recall':
            score = recall_score(y_true, y_pred, zero_division=0)
        
        if score > best_score:
            best_score = score
            best_threshold = threshold
    
    return best_threshold, best_score

Trade-offs entre Métricas

Al ajustar thresholds, es importante entender los trade-offs:

  • Threshold más bajo: Mayor recall, menor precision
  • Threshold más alto: Mayor precision, menor recall
  • F1-Score: Busca equilibrio entre ambas métricas

Implementación Práctica Completa

Evaluación Integral de un Modelo

Para una evaluación completa, especialmente con datasets desbalanceados:

from sklearn.metrics import classification_report, confusion_matrix

def evaluate_comprehensive(y_true, y_pred, y_pred_proba=None):
    # Matriz de confusión
    cm = confusion_matrix(y_true, y_pred)
    tn, fp, fn, tp = cm.ravel()
    
    # Métricas básicas
    accuracy = accuracy_score(y_true, y_pred)
    precision = precision_score(y_true, y_pred)
    recall = recall_score(y_true, y_pred)
    f1 = f1_score(y_true, y_pred)
    specificity = tn / (tn + fp)
    
    # ROC-AUC si hay probabilidades
    if y_pred_proba is not None:
        fpr, tpr, _ = roc_curve(y_true, y_pred_proba)
        roc_auc = auc(fpr, tpr)
    
    # Reporte detallado
    print(classification_report(y_true, y_pred))
    
    return {
        'confusion_matrix': cm,
        'accuracy': accuracy,
        'precision': precision,
        'recall': recall,
        'f1_score': f1,
        'specificity': specificity,
        'roc_auc': roc_auc if y_pred_proba is not None else None
    }

Recomendaciones para Diferentes Escenarios

EscenarioMétrica PrincipalConsideraciones
Dataset balanceadoAccuracy, F1-ScoreTodas las métricas son confiables
Dataset desbalanceadoPrecision, Recall, F1-Score, AUC-ROCEvitar accuracy como métrica única
Detección de fraudeRecall (alta sensibilidad)No perder casos positivos
Diagnóstico médicoPrecision y Recall equilibradasBalance entre falsos positivos/negativos
Filtro de spamPrecision (baja FPR)Evitar clasificar emails legítimos como spam

Las métricas de evaluación son herramientas poderosas que nos permiten entender el verdadero rendimiento de nuestros modelos. La clave está en seleccionar las métricas apropiadas según el contexto del problema, la distribución de las clases y los costos asociados a diferentes tipos de errores. El ajuste de thresholds y el uso de múltiples métricas complementarias proporcionan una visión más completa y confiable del rendimiento del modelo.

Métricas de Evaluación en Machine Learning - Matriz de Confusión y ROC-AUC

Author

Juan Fuentes

Publish Date

06 - 10 - 2023