Curva AUC – ROC en Python

En la clasificación, hay muchas métricas de evaluación diferentes. El más popular es la precisión, que mide la frecuencia con la que el modelo es correcto. Esta es una gran métrica porque es fácil de entender y a menudo se desea obtener las conjeturas más correctas. Hay algunos casos en los que podría considerar usar otra métrica de evaluación.

Otra métrica común es AUC, área bajo la curva característica operativa del receptor (ROC). La curva característica operativa del Reciever traza la tasa de verdaderos positivos (TP) frente a la tasa de falsos positivos (FP) en diferentes umbrales de clasificación. Los umbrales son diferentes puntos de corte de probabilidad que separan las dos clases en la clasificación binaria. Utiliza la probabilidad para decirnos qué tan bien un modelo separa las clases.

Datos desequilibrados

Supongamos que tenemos un conjunto de datos desequilibrado donde la mayoría de nuestros datos tienen un valor. Podemos obtener una alta precisión para el modelo prediciendo la clase mayoritaria.

Ejemplo

import numpy as np
from sklearn.metrics import accuracy_score, confusion_matrix, roc_auc_score, roc_curve

n = 10000
ratio = .95
n_0 = int((1-ratio) * n)
n_1 = int(ratio * n)

y = np.array([0] * n_0 + [1] * n_1)
# below are the probabilities obtained from a hypothetical model that always predicts the majority class
# probability of predicting class 1 is going to be 100%
y_proba = np.array([1]*n)
y_pred = y_proba > .5

print(f'accuracy score: {accuracy_score(y, y_pred)}')
cf_mat = confusion_matrix(y, y_pred)
print('Confusion matrix')
print(cf_mat)
print(f'class 0 accuracy: {cf_mat[0][0]/n_0}')
print(f'class 1 accuracy: {cf_mat[1][1]/n_1}')

Aunque obtenemos una precisión muy alta, el modelo no proporcionó información sobre los datos, por lo que no es útil. Predecimos con precisión la clase 1 el 100 % de las veces, mientras que predecimos de forma imprecisa la clase 0 el 0 % de las veces. A expensas de la precisión, podría ser mejor tener un modelo que pueda separar un poco las dos clases.

Ejemplo

# below are the probabilities obtained from a hypothetical model that doesn't always predict the mode
y_proba_2 = np.array(
    np.random.uniform(0, .7, n_0).tolist() +
    np.random.uniform(.3, 1, n_1).tolist()
)
y_pred_2 = y_proba_2 > .5

print(f'accuracy score: {accuracy_score(y, y_pred_2)}')
cf_mat = confusion_matrix(y, y_pred_2)
print('Confusion matrix')
print(cf_mat)
print(f'class 0 accuracy: {cf_mat[0][0]/n_0}')
print(f'class 1 accuracy: {cf_mat[1][1]/n_1}')

Para el segundo conjunto de predicciones, no tenemos un puntaje de precisión tan alto como el primero, pero la precisión para cada clase es más equilibrada. Utilizando la precisión como una métrica de evaluación, calificaríamos el primer modelo más alto que el segundo, aunque no nos diga nada sobre los datos.

En casos como este, sería preferible utilizar otra métrica de evaluación como AUC.

import matplotlib.pyplot as plt

def plot_roc_curve(true_y, y_prob):
    """
    plots the roc curve based of the probabilities
    """

    fpr, tpr, thresholds = roc_curve(true_y, y_prob)
    plt.plot(fpr, tpr)
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')

Ejemplo

Modelo 1

plot_roc_curve(y, y_proba)
print(f'model 1 AUC score: {roc_auc_score(y, y_proba)}')

Resultado

puntuación AUC del modelo 1: 0,5

Ejemplo

Modelo 2

plot_roc_curve(y, y_proba_2)
print(f'model 2 AUC score: {roc_auc_score(y, y_proba_2)}')

Resultado

puntuación AUC del modelo 2: 0,8270551578947367

Una puntuación de AUC de alrededor de 0,5 significaría que el modelo no puede distinguir entre las dos clases y la curva se vería como una línea con una pendiente de 1. Una puntuación de AUC más cercana a 1 significa que el modelo tiene la capacidad de separe las dos clases y la curva se acercará a la esquina superior izquierda del gráfico.

Probabilidades

Debido a que AUC es una métrica que utiliza las probabilidades de las predicciones de clase, podemos confiar más en un modelo que tiene una puntuación de AUC más alta que en uno con una puntuación más baja, incluso si tienen precisiones similares.

En los datos a continuación, tenemos dos conjuntos de probabilidades de modelos hipotéticos. El primero tiene probabilidades que no son tan «seguras» al predecir las dos clases (las probabilidades están cerca de .5). El segundo tiene probabilidades que son más «seguras» al predecir las dos clases (las probabilidades están cerca de los extremos de 0 o 1).

Ejemplo

import numpy as np

n = 10000
y = np.array([0] * n + [1] * n)
#
y_prob_1 = np.array(
    np.random.uniform(.25, 5, n//2).tolist() +
    np.random.uniform(.3, .7, n).tolist() +
    np.random.uniform(.5, .75, n//2).tolist()
)
y_prob_2 = np.array(
    np.random.uniform(0, .4, n//2).tolist() +
    np.random.uniform(.3, .7, n).tolist() +
    np.random.uniform(.6, 1, n//2).tolist()
)

print(f'model 1 accuracy score: {accuracy_score(y, y_prob_1>.5)}')
print(f'model 2 accuracy score: {accuracy_score(y, y_prob_2>.5)}')

print(f'model 1 AUC score: {roc_auc_score(y, y_prob_1)}')
print(f'model 2 AUC score: {roc_auc_score(y, y_prob_2)}')

Ejemplo

Modelo de trama 1:

plot_roc_curve(y, y_prob_1)

Ejemplo

Modelo de trama 2:

fpr, tpr, thresholds = roc_curve(y, y_prob_2)
plt.plot(fpr, tpr)

Aunque las precisiones de los dos modelos son similares, el modelo con la puntuación AUC más alta será más fiable porque tiene en cuenta la probabilidad predicha. Es más probable que le brinde una mayor precisión al predecir datos futuros.