Cómo trazar la curva ROC en Python

83

Estoy tratando de trazar una curva ROC para evaluar la precisión de un modelo de predicción que desarrollé en Python usando paquetes de regresión logística. He calculado la tasa de verdaderos positivos así como la tasa de falsos positivos; sin embargo, no puedo averiguar cómo trazarlos correctamente usando matplotliby calcular el valor AUC. ¿Cómo puedo hacer eso?

usuario3847447
fuente

Respuestas:

106

Aquí hay dos formas en las que puede intentarlo, asumiendo que modeles un predictor de sklearn:

import sklearn.metrics as metrics
# calculate the fpr and tpr for all thresholds of the classification
probs = model.predict_proba(X_test)
preds = probs[:,1]
fpr, tpr, threshold = metrics.roc_curve(y_test, preds)
roc_auc = metrics.auc(fpr, tpr)

# method I: plt
import matplotlib.pyplot as plt
plt.title('Receiver Operating Characteristic')
plt.plot(fpr, tpr, 'b', label = 'AUC = %0.2f' % roc_auc)
plt.legend(loc = 'lower right')
plt.plot([0, 1], [0, 1],'r--')
plt.xlim([0, 1])
plt.ylim([0, 1])
plt.ylabel('True Positive Rate')
plt.xlabel('False Positive Rate')
plt.show()

# method II: ggplot
from ggplot import *
df = pd.DataFrame(dict(fpr = fpr, tpr = tpr))
ggplot(df, aes(x = 'fpr', y = 'tpr')) + geom_line() + geom_abline(linetype = 'dashed')

o tratar

ggplot(df, aes(x = 'fpr', ymin = 0, ymax = 'tpr')) + geom_line(aes(y = 'tpr')) + geom_area(alpha = 0.2) + ggtitle("ROC Curve w/ AUC = %s" % str(roc_auc)) 
Uniquegino
fuente
Entonces, 'preds' es básicamente tu puntaje de predict_proba y 'model' es tu clasificador.
Chris Nielsen
@ChrisNielsen prepara su sombrero; sí, el modelo es el clasificador entrenado
uniquegino
¿Qué es all thresholds, cómo se calculan?
mrgloom
@mrgloom son elegidos automáticamente por sklearn.metrics.roc_curve
erobertc
85

Esta es la forma más sencilla de trazar una curva ROC, dado un conjunto de etiquetas de verdad del terreno y probabilidades predichas. La mejor parte es que traza la curva ROC para TODAS las clases, por lo que también obtiene múltiples curvas de aspecto ordenado

import scikitplot as skplt
import matplotlib.pyplot as plt

y_true = # ground truth labels
y_probas = # predicted probabilities generated by sklearn classifier
skplt.metrics.plot_roc_curve(y_true, y_probas)
plt.show()

Aquí hay una curva de muestra generada por plot_roc_curve. Usé el conjunto de datos de dígitos de muestra de scikit-learn, por lo que hay 10 clases. Observe que se traza una curva ROC para cada clase.

Curvas ROC

Descargo de responsabilidad: tenga en cuenta que esto usa la biblioteca scikit-plot , que construí.

Reii Nakano
fuente
2
¿Cómo calcular y_true ,y_probas ?
Md. Rezwanul Haque
3
Reii Nakano - Eres un genio disfrazado de ángel. Me has hecho el día. Este paquete es tan simple pero tan efectivo. Tienes todo mi respeto. Solo una pequeña nota sobre el fragmento de código anterior; la línea anterior a la última, ¿no debería leer skplt.metrics.plot_roc_curve(y_true, y_probas):? Un gran gracias.
salvu
1
¡Esto debería haber sido seleccionado como la respuesta correcta! Paquete muy útil
Srivathsa
20
Tengo problemas al intentar usar package. Cada vez que intento alimentar la curva del roc de la trama, me dice que tengo "demasiados índices". Estoy alimentando el my_test y, pred to it. Puedo tener mis predicciones. Pero no puedo entender la trama debido a ese error. ¿Es debido a la versión de Python que estoy ejecutando?
Herc01
3
Tuve que remodelar mis datos y_pred para que fueran de tamaño Nx1 en lugar de solo una lista: y_pred.reshape (len (y_pred), 1). Ahora, en cambio, obtengo el error 'IndexError: el índice 1 está fuera de los límites para el eje 1 con tamaño 1', pero se dibuja una figura, que supongo que se debe a que el código espera que un clasificador binario proporcione un vector Nx2 con cada probabilidad de clase
Vidar
40

No está del todo claro cuál es el problema aquí, pero si tiene una matriz true_positive_ratey una matriz false_positive_rate, entonces trazar la curva ROC y obtener el AUC es tan simple como:

import matplotlib.pyplot as plt
import numpy as np

x = # false_positive_rate
y = # true_positive_rate 

# This is the ROC curve
plt.plot(x,y)
plt.show() 

# This is the AUC
auc = np.trapz(y,x)
pendiente
fuente
6
esta respuesta habría sido mucho mejor si hubiera FPR, TPR oneliners en el código.
Aerin
11
fpr, tpr, umbral = metrics.roc_curve (y_test, preds)
Aerin
¿Qué significa "métricas" aquí? ¿Qué es eso exactamente?
dekio
1
@dekio 'metrics' aquí es de sklearn: de sklearn import metrics
Baptiste Pouthier
38

Curva AUC para clasificación binaria usando matplotlib

from sklearn import svm, datasets
from sklearn import metrics
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
import matplotlib.pyplot as plt

Cargar conjunto de datos de cáncer de mama

breast_cancer = load_breast_cancer()

X = breast_cancer.data
y = breast_cancer.target

Dividir el conjunto de datos

X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.33, random_state=44)

Modelo

clf = LogisticRegression(penalty='l2', C=0.1)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)

Exactitud

print("Accuracy", metrics.accuracy_score(y_test, y_pred))

Curva AUC

y_pred_proba = clf.predict_proba(X_test)[::,1]
fpr, tpr, _ = metrics.roc_curve(y_test,  y_pred_proba)
auc = metrics.roc_auc_score(y_test, y_pred_proba)
plt.plot(fpr,tpr,label="data 1, auc="+str(auc))
plt.legend(loc=4)
plt.show()

Curva AUC

ajayramesh
fuente
19

Aquí está el código de Python para calcular la curva ROC (como un diagrama de dispersión):

import matplotlib.pyplot as plt
import numpy as np

score = np.array([0.9, 0.8, 0.7, 0.6, 0.55, 0.54, 0.53, 0.52, 0.51, 0.505, 0.4, 0.39, 0.38, 0.37, 0.36, 0.35, 0.34, 0.33, 0.30, 0.1])
y = np.array([1,1,0, 1, 1, 1, 0, 0, 1, 0, 1,0, 1, 0, 0, 0, 1 , 0, 1, 0])

# false positive rate
fpr = []
# true positive rate
tpr = []
# Iterate thresholds from 0.0, 0.01, ... 1.0
thresholds = np.arange(0.0, 1.01, .01)

# get number of positive and negative examples in the dataset
P = sum(y)
N = len(y) - P

# iterate through all thresholds and determine fraction of true positives
# and false positives found at this threshold
for thresh in thresholds:
    FP=0
    TP=0
    for i in range(len(score)):
        if (score[i] > thresh):
            if y[i] == 1:
                TP = TP + 1
            if y[i] == 0:
                FP = FP + 1
    fpr.append(FP/float(N))
    tpr.append(TP/float(P))

plt.scatter(fpr, tpr)
plt.show()
Mona
fuente
Usó el mismo índice de bucle externo "i" en el bucle interno también.
Ali Yeşilkanat
La referencia es 404.
luckydonald
@Mona, gracias por señalar cómo funciona un algoritmo.
user3225309
9
from sklearn import metrics
import numpy as np
import matplotlib.pyplot as plt

y_true = # true labels
y_probas = # predicted results
fpr, tpr, thresholds = metrics.roc_curve(y_true, y_probas, pos_label=0)

# Print ROC curve
plt.plot(fpr,tpr)
plt.show() 

# Print AUC
auc = np.trapz(tpr,fpr)
print('AUC:', auc)
Cereza Wu
fuente
2
¿Cómo calcular y_true = # true labels, y_probas = # predicted results?
Md. Rezwanul Haque
2
Si tiene la verdad básica, y_true es su verdad básica (etiqueta), y_probas son los resultados predichos de su modelo
Cherry Wu
6

Las respuestas anteriores suponen que usted mismo calculó TP / Sens. Es una mala idea hacer esto manualmente, es fácil cometer errores con los cálculos, en lugar de usar una función de biblioteca para todo esto.

la función plot_roc en scikit_lean hace exactamente lo que necesitas: http://scikit-learn.org/stable/auto_examples/model_selection/plot_roc.html

La parte esencial del código es:

  for i in range(n_classes):
      fpr[i], tpr[i], _ = roc_curve(y_test[:, i], y_score[:, i])
      roc_auc[i] = auc(fpr[i], tpr[i])
Max
fuente
¿Cómo calcular y_score?
Saeed
6

Basado en múltiples comentarios de stackoverflow, documentación de scikit-learn y algunos otros, hice un paquete de Python para trazar la curva ROC (y otra métrica) de una manera realmente simple.

Para instalar el paquete: pip install plot-metric(más información al final de la publicación)

Para trazar una curva ROC (el ejemplo proviene de la documentación):

Clasificación binaria

Carguemos un conjunto de datos simple y hagamos un tren y un conjunto de prueba:

from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
X, y = make_classification(n_samples=1000, n_classes=2, weights=[1,1], random_state=1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=2)

Entrene un clasificador y prediga el conjunto de pruebas:

from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(n_estimators=50, random_state=23)
model = clf.fit(X_train, y_train)

# Use predict_proba to predict probability of the class
y_pred = clf.predict_proba(X_test)[:,1]

Ahora puede usar plot_metric para trazar la curva ROC:

from plot_metric.functions import BinaryClassification
# Visualisation with plot_metric
bc = BinaryClassification(y_test, y_pred, labels=["Class 1", "Class 2"])

# Figures
plt.figure(figsize=(5,5))
bc.plot_roc_curve()
plt.show()

Resultado: Curva ROC

Puede encontrar más ejemplos en github y la documentación del paquete:

Yohann L.
fuente
He intentado esto y es bueno, pero no parece que funcione solo si las etiquetas de clasificación eran 0 o 1, pero si tengo 1 y 2 no funciona (como etiquetas), ¿sabes cómo resolver esto? y también parece imposible editar el gráfico (como la leyenda)
Reut
4

He creado una función simple incluida en un paquete para la curva ROC. Acabo de comenzar a practicar el aprendizaje automático, así que por favor, avíseme también si este código tiene algún problema.

¡Eche un vistazo al archivo léame de github para obtener más detalles! :)

https://github.com/bc123456/ROC

from sklearn.metrics import confusion_matrix, accuracy_score, roc_auc_score, roc_curve
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

def plot_ROC(y_train_true, y_train_prob, y_test_true, y_test_prob):
    '''
    a funciton to plot the ROC curve for train labels and test labels.
    Use the best threshold found in train set to classify items in test set.
    '''
    fpr_train, tpr_train, thresholds_train = roc_curve(y_train_true, y_train_prob, pos_label =True)
    sum_sensitivity_specificity_train = tpr_train + (1-fpr_train)
    best_threshold_id_train = np.argmax(sum_sensitivity_specificity_train)
    best_threshold = thresholds_train[best_threshold_id_train]
    best_fpr_train = fpr_train[best_threshold_id_train]
    best_tpr_train = tpr_train[best_threshold_id_train]
    y_train = y_train_prob > best_threshold

    cm_train = confusion_matrix(y_train_true, y_train)
    acc_train = accuracy_score(y_train_true, y_train)
    auc_train = roc_auc_score(y_train_true, y_train)

    print 'Train Accuracy: %s ' %acc_train
    print 'Train AUC: %s ' %auc_train
    print 'Train Confusion Matrix:'
    print cm_train

    fig = plt.figure(figsize=(10,5))
    ax = fig.add_subplot(121)
    curve1 = ax.plot(fpr_train, tpr_train)
    curve2 = ax.plot([0, 1], [0, 1], color='navy', linestyle='--')
    dot = ax.plot(best_fpr_train, best_tpr_train, marker='o', color='black')
    ax.text(best_fpr_train, best_tpr_train, s = '(%.3f,%.3f)' %(best_fpr_train, best_tpr_train))
    plt.xlim([0.0, 1.0])
    plt.ylim([0.0, 1.0])
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')
    plt.title('ROC curve (Train), AUC = %.4f'%auc_train)

    fpr_test, tpr_test, thresholds_test = roc_curve(y_test_true, y_test_prob, pos_label =True)

    y_test = y_test_prob > best_threshold

    cm_test = confusion_matrix(y_test_true, y_test)
    acc_test = accuracy_score(y_test_true, y_test)
    auc_test = roc_auc_score(y_test_true, y_test)

    print 'Test Accuracy: %s ' %acc_test
    print 'Test AUC: %s ' %auc_test
    print 'Test Confusion Matrix:'
    print cm_test

    tpr_score = float(cm_test[1][1])/(cm_test[1][1] + cm_test[1][0])
    fpr_score = float(cm_test[0][1])/(cm_test[0][0]+ cm_test[0][1])

    ax2 = fig.add_subplot(122)
    curve1 = ax2.plot(fpr_test, tpr_test)
    curve2 = ax2.plot([0, 1], [0, 1], color='navy', linestyle='--')
    dot = ax2.plot(fpr_score, tpr_score, marker='o', color='black')
    ax2.text(fpr_score, tpr_score, s = '(%.3f,%.3f)' %(fpr_score, tpr_score))
    plt.xlim([0.0, 1.0])
    plt.ylim([0.0, 1.0])
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')
    plt.title('ROC curve (Test), AUC = %.4f'%auc_test)
    plt.savefig('ROC', dpi = 500)
    plt.show()

    return best_threshold

Un gráfico roc de muestra producido por este código

Brian Chan
fuente
¿Cómo calcular y_train_true, y_train_prob, y_test_true, y_test_prob?
Md. Rezwanul Haque
y_train_true, y_test_truedebe estar disponible en un conjunto de datos etiquetado. y_train_prob, y_test_probson salidas de su red neuronal entrenada.
Brian Chan
-1

Hay una biblioteca llamada metriculous que lo hará por usted:

$ pip install metriculous

Primero hagamos una simulación de algunos datos, esto generalmente vendría del conjunto de datos de prueba y del modelo (s):

import numpy as np

def normalize(array2d: np.ndarray) -> np.ndarray:
    return array2d / array2d.sum(axis=1, keepdims=True)

class_names = ["Cat", "Dog", "Pig"]
num_classes = len(class_names)
num_samples = 500

# Mock ground truth
ground_truth = np.random.choice(range(num_classes), size=num_samples, p=[0.5, 0.4, 0.1])

# Mock model predictions
perfect_model = np.eye(num_classes)[ground_truth]
noisy_model = normalize(
    perfect_model + 2 * np.random.random((num_samples, num_classes))
)
random_model = normalize(np.random.random((num_samples, num_classes)))

Ahora podemos usar metriculous para generar una tabla con varias métricas y diagramas, incluidas las curvas ROC:

import metriculous

metriculous.compare_classifiers(
    ground_truth=ground_truth,
    model_predictions=[perfect_model, noisy_model, random_model],
    model_names=["Perfect Model", "Noisy Model", "Random Model"],
    class_names=class_names,
    one_vs_all_figures=True, # This line is important to include ROC curves in the output
).save_html("model_comparison.html").display()

Las curvas ROC en la salida: curvas ROC métricas

Los gráficos se pueden ampliar y arrastrar, y obtienes más detalles al pasar el mouse sobre el gráfico:

curva ROC métrica

efjnvdslndf
fuente