Jak wykreślić krzywą ROC w Pythonie

88

Próbuję wykreślić krzywą ROC, aby ocenić dokładność modelu predykcyjnego, który opracowałem w Pythonie przy użyciu pakietów regresji logistycznej. Obliczyłem odsetek prawdziwie pozytywnych i fałszywie pozytywnych; jednakże, nie jestem w stanie dowiedzieć się, jak wykreślić je poprawnie, używając matplotlibi obliczyć wartość AUC. Jak mogłem to zrobić?

user3847447
źródło

Odpowiedzi:

110

Oto dwa sposoby, które możesz wypróbować, zakładając, że modeljesteś predyktorem 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')

lub spróbuj

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
źródło
Czyli „preds” to w zasadzie wyniki „Predict_proba”, a „model” to klasyfikator?
Chris Nielsen,
@ChrisNielsen preds is y hat; tak, model jest wyszkolonym klasyfikatorem
uniquegino
Co to jest all thresholds, jak są obliczane?
mrgloom
@mrgloom są wybierane automatycznie przez sklearn.metrics.roc_curve
erobertc
88

Jest to najprostszy sposób na wykreślenie krzywej ROC, biorąc pod uwagę zestaw podstawowych etykiet i przewidywanych prawdopodobieństw. Najlepsze jest to, że wykreśla krzywą ROC dla WSZYSTKICH klas, więc otrzymujesz również wiele ładnie wyglądających krzywych

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()

Oto przykładowa krzywa wygenerowana przez plot_roc_curve. Użyłem zestawu danych przykładowych cyfr ze scikit-learn, więc jest 10 klas. Zauważ, że dla każdej klasy wykreślana jest jedna krzywa ROC.

Krzywe ROC

Zastrzeżenie: Zauważ, że używa to biblioteki scikit-plot , którą zbudowałem.

Reii Nakano
źródło
3
Jak obliczyć y_true ,y_probas ?
Md. Rezwanul Haque
3
Reii Nakano - jesteś geniuszem w przebraniu anioła. Uczyniłeś mój dzień. Ten pakiet jest bardzo prosty, ale jednocześnie tak skuteczny. Masz mój pełen szacunek. Tylko mała uwaga na temat powyższego fragmentu kodu; wiersz przed ostatnim shouln't to przeczytać: skplt.metrics.plot_roc_curve(y_true, y_probas)? Wielkie dzięki.
salvu
1
To powinno być wybrane jako poprawna odpowiedź! Bardzo przydatny pakiet
Srivathsa
24
Mam problemy podczas próby użycia pakietu. Za każdym razem, gdy próbuję podać krzywą wykresu rok, mówi mi, że mam „za dużo wskaźników”. Karmię mój y_test i przed nim. Jestem w stanie spełnić moje przewidywania. Ale nie mogę zrozumieć fabuły z powodu tego błędu. Czy jest to spowodowane wersją Pythona, którą używam?
Herc01
4
Musiałem zmienić kształt moich danych y_pred, aby miały rozmiar Nx1 zamiast tylko listy: y_pred.reshape (len (y_pred), 1). Teraz zamiast tego otrzymuję błąd `` IndexError: index 1 is out of bounds for axis 1 with size 1 '', ale rysowana jest liczba, co, jak sądzę, jest spowodowane tym, że kod oczekuje, że klasyfikator binarny zapewni wektor Nx2 z prawdopodobieństwem każdej klasy
Vidar,
42

Wcale nie jest jasne, na czym polega problem, ale jeśli masz tablicę true_positive_ratei tablicę false_positive_rate, wykreślenie krzywej ROC i uzyskanie AUC jest tak proste, jak:

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)
ebarr
źródło
8
ta odpowiedź byłaby znacznie lepsza, gdyby w kodzie znajdowały się oneliny FPR, TPR.
Aerin
12
FPR TPR, Próg = metrics.roc_curve (y_test, preds)
Aerin
co oznaczają tutaj „metryki”? co to dokładnie jest
dekio
1
@dekio 'metrics' tutaj pochodzi ze sklearn: from sklearn import metrics
Baptiste Pouthier,
39

Krzywa AUC dla klasyfikacji binarnej przy użyciu 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

Załaduj zbiór danych raka piersi

breast_cancer = load_breast_cancer()

X = breast_cancer.data
y = breast_cancer.target

Podziel zbiór danych

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

Model

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

Precyzja

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

Krzywa 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()

Krzywa AUC

ajayramesh
źródło
19

Oto kod Pythona do obliczania krzywej ROC (jako wykres punktowy):

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
źródło
Użyłeś tego samego indeksu zewnętrznej pętli „i” w pętli wewnętrznej.
Ali Yeşilkanat
Odniesienie to 404.
luckydonald
@Mona, dzięki za wskazanie, jak działa algorytm.
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)
Cherry Wu
źródło
2
Jak obliczyć y_true = # true labels, y_probas = # predicted results?
Md. Rezwanul Haque
2
Jeśli masz podstawową prawdę, y_true to twoja podstawowa prawda (etykieta), y_probas to przewidywane wyniki z twojego modelu
Cherry Wu
6

Poprzednie odpowiedzi zakładają, że rzeczywiście samodzielnie obliczyłeś TP / Sens. To zły pomysł, aby zrobić to ręcznie, łatwo jest popełnić błędy w obliczeniach, raczej użyj do tego funkcji biblioteki.

funkcja plot_roc w scikit_lean robi dokładnie to, czego potrzebujesz: http://scikit-learn.org/stable/auto_examples/model_selection/plot_roc.html

Zasadniczą częścią kodu jest:

  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])
Maks
źródło
Jak obliczyć y_score?
Saeed
6

Opierając się na wielu komentarzach z stackoverflow, dokumentacji scikit-learn i kilku innych, stworzyłem pakiet Pythona do wykreślania krzywej ROC (i innych metryk) w naprawdę prosty sposób.

Aby zainstalować pakiet: pip install plot-metric (więcej informacji na końcu postu)

Aby wykreślić krzywą ROC (przykład pochodzi z dokumentacji):

Klasyfikacja binarna

Załadujmy prosty zbiór danych i stwórzmy zestaw pociągów i testów:

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)

Wytrenuj klasyfikator i przewiduj zbiór testów:

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]

Możesz teraz używać plot_metric do kreślenia krzywej 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()

Wynik: Krzywa ROC

Możesz znaleźć więcej przykładów na githubie oraz dokumentację pakietu:

Yohann L.
źródło
Próbowałem tego i jest fajnie, ale nie wygląda na to, że działa tylko wtedy, gdy etykiety klasyfikacyjne były 0 lub 1, ale jeśli mam 1 i 2, nie działa (jako etykiety), czy wiesz, jak to rozwiązać? a także wydaje się niemożliwe do edycji wykresu (jak legenda)
Reut
4

Zrobiłem prostą funkcję zawartą w pakiecie dla krzywej ROC. Właśnie zacząłem ćwiczyć uczenie maszynowe, więc daj mi również znać, jeśli ten kod ma jakiś problem!

Więcej informacji znajdziesz w pliku readme na githubie! :)

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

Przykładowy wykres roc utworzony przez ten kod

Brian Chan
źródło
Jak obliczyć y_train_true, y_train_prob, y_test_true, y_test_prob?
Md. Rezwanul Haque
y_train_true, y_test_truepowinny być łatwo dostępne w oznaczonym zbiorze danych. y_train_prob, y_test_probsą danymi wyjściowymi z wytrenowanej sieci neuronowej.
Brian Chan,
0

Kiedy potrzebujesz również prawdopodobieństw ... Poniższy rysunek pobiera wartość AUC i przedstawia to wszystko w jednym ujęciu.

from sklearn.metrics import plot_roc_curve

plot_roc_curve(m,xs,y)

Kiedy masz prawdopodobieństwa ... nie możesz uzyskać wartości auc i wykresów za jednym zamachem. Wykonaj następujące czynności:

from sklearn.metrics import roc_curve

fpr,tpr,_ = roc_curve(y,y_probas)
plt.plot(fpr,tpr, label='AUC = ' + str(round(roc_auc_score(y,m.oob_decision_function_[:,1]), 2)))
plt.legend(loc='lower right')
agent18
źródło
-1

Istnieje biblioteka o nazwie metriculous , która zrobi to za Ciebie:

$ pip install metriculous

Najpierw sfałszujmy niektóre dane, zwykle pochodzą one z testowego zestawu danych i modeli:

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)))

Teraz możemy użyć metriculous do wygenerowania tabeli z różnymi metrykami i diagramami, w tym krzywymi 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()

Krzywe ROC na wyjściu: metryczne krzywe ROC

Działki można powiększać i przeciągać, a dodatkowe szczegóły można uzyskać, umieszczając kursor myszy nad wykresem:

metryczna krzywa ROC

efjnvdslndf
źródło