He utilizado sklearn para calcular roc_auc_score
para un conjunto de datos de 72 casos. La precisión fue del 97% (2 errores de clasificación), pero la puntuación ROC AUC fue de 1,0. ¿Cómo es posible? Yo pensaría que incluso una clasificación errónea debería haber reducido la puntuación ligeramente por debajo de 1,0.
# Python 3.6.4
# numpy==1.14.3
# scikit-learn==0.19.1
# scipy==1.1.0
from sklearn import metrics
import numpy as np
y_true = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0])
y_prob = np.array([0.0, 0.1, 0.0, 0.0, 0.0, 0.0, 0.1, 0.0, 0.1, 0.0, 0.0, 0.0, 0.0, 0.7, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.1, 0.1, 0.0, 0.0, 0.9, 0.0, 0.0, 0.0, 0.0, 0.1, 0.0, 0.0, 0.0, 0.1, 0.1, 0.0, 0.0, 0.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.1, 0.0, 0.0, 0.0, 0.0, 0.1, 0.0, 0.0, 0.1, 0.1, 0.0, 0.9, 0.0, 0.0, 0.4, 0.0, 0.0, 0.0])
# Show which actuals do not match their expected probabilities
for index, (actual, predicted_prob) in enumerate(zip(y_true, y_prob)):
if (actual == 1 and predicted_prob <= 0.5) or (actual == 0 and predicted_prob > 0.5):
print (f'Mismatch at index {index}. Actual={actual}, predicted_prob={predicted_prob}')
rocauc = metrics.roc_auc_score(y_true, y_prob)
print (f'ROCAUC: {rocauc}')
# Outputs:
# Mismatch at index 14. Actual=1.0, predicted_prob=0.5
# Mismatch at index 68. Actual=1.0, predicted_prob=0.4
# ROCAUC: 1.0
A continuación, he depurado el propio cálculo de la puntuación y he mirado la salida ROC de coordenadas.
# In sklearn/metrics/ranking.py, line 271:
--> 271 fpr, tpr, tresholds = roc_curve(y_true, y_score,
272 sample_weight=sample_weight)
ipdb> fpr
array([0. , 0. , 0. , 0.18181818, 1. ])
ipdb> tpr
array([0.33333333, 0.66666667, 1. , 1. , 1. ])
ipdb> tresholds
array([0.9, 0.7, 0.4, 0.1, 0. ])
# coords = []
# for x, y in zip(fpr, tpr):
# coords.append((x, y))
ipdb> pp coords
[(0.0, 0.3333333333333333),
(0.0, 0.6666666666666666),
(0.0, 1.0),
(0.18181818181818182, 1.0),
(1.0, 1.0)]
Todas esas coordenadas están en x=0 o y=1, lo que significa que ROCAUC muestra 1,0. La única explicación plausible que se me ocurre es que si el alg tuviera más puntos fpr/tpr, mostraría una curva muy cerrada que nunca llegaría a x,y = (0, 1), y el ROCAUC se acercaría a 1, pero no exactamente a 1. ¿Es esa una interpretación razonable o me estoy perdiendo algo?