Scikit-learn e Yellowbrick danno punteggi diversi

Nov 02 2020

Sto usando sklearn per calcolare la precisione media e roc_auc di un classificatore e yellowbrick per tracciare le curve roc_auc e di richiamo di precisione. Il problema è che i pacchetti danno punteggi diversi in entrambe le metriche e non so quale sia quello corretto.

Il codice utilizzato:

import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from yellowbrick.classifier import ROCAUC
from yellowbrick.classifier import PrecisionRecallCurve
from sklearn.datasets import make_classification
from sklearn.metrics import roc_auc_score
from sklearn.metrics import average_precision_score

seed = 42

# provides de data
X, y = make_classification(n_samples=1000, n_features=2, n_redundant=0,
                           n_informative=2, random_state=seed)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

clf_lr = LogisticRegression(random_state=seed)
clf_lr.fit(X_train, y_train)

y_pred = clf_lr.predict(X_test)
roc_auc = roc_auc_score(y_test, y_pred)
avg_precision = average_precision_score(y_test, y_pred)
print(f"ROC_AUC: {roc_auc}")
print(f"Average_precision: {avg_precision}")
print('='*20)

# visualizations
viz3 = ROCAUC(LogisticRegression(random_state=seed))
viz3.fit(X_train, y_train) 
viz3.score(X_test, y_test)
viz3.show()
viz4 = PrecisionRecallCurve(LogisticRegression(random_state=seed))
viz4.fit(X_train, y_train)
viz4.score(X_test, y_test)
viz4.show()

Il codice produce il seguente output:

Come si può vedere sopra, le metriche danno valori diversi a seconda del pacchetto. Nell'istruzione print ci sono i valori calcolati da scikit-learn mentre nei grafici appaiono annotati i valori calcolati da yellowbrick.

Risposte

1 desertnaut Nov 03 2020 at 05:29

Dato che usi il predictmetodo di scikit-learn, le tue previsioni y_predsono appartenenze a classi dure e non probabilità:

np.unique(y_pred)
# array([0, 1])

Ma per i calcoli ROC e Precision-Recall, questo non dovrebbe essere il caso; le previsioni che passi a questi metodi dovrebbero essere probabilità e non classi rigide. Dai average_precision_score documenti :

y_score: array, shape = [n_samples] o [n_samples, n_classes]

I punteggi target possono essere stime di probabilità della classe positiva, valori di confidenza o misura delle decisioni senza soglia (come restituito da "decision_function" su alcuni classificatori).

dove senza soglia significa esattamente non classi difficili . Simile è il caso di roc_auc_score( docs ).

Correggendo questo con il seguente codice, i risultati di scikit-learn sono identici a quelli restituiti da Yellowbrick:

y_pred = clf_lr.predict_proba(X_test)     # get probabilities
y_prob = np.array([x[1] for x in y_pred]) # keep the prob for the positive class 1
roc_auc = roc_auc_score(y_test, y_prob)
avg_precision = average_precision_score(y_test, y_prob)
print(f"ROC_AUC: {roc_auc}")
print(f"Average_precision: {avg_precision}")

Risultati:

ROC_AUC: 0.9545954595459546
Average_precision: 0.9541994473779806

Poiché Yellowbrick gestisce tutti questi dettagli computazionali internamente (e in modo trasparente), non soffre dell'errore nella procedura manuale di scikit-learn fatta qui.


Nota che, nel caso binario (come qui), puoi (e dovresti) rendere i tuoi grafici meno ingombri con l' binary=Trueargomento:

viz3 = ROCAUC(LogisticRegression(random_state=seed), binary=True) # similarly for the PrecisionRecall curve

e che, contrariamente a quanto si aspetterebbe migh intuitivamente, per il caso binario almeno, il scoremetodo ROCAUCsarà non restituire l'AUC, ma la precisione, come specificato nelle documenti :

viz3.score(X_test, y_test)
# 0.88

# verify this is the accuracy:

from sklearn.metrics import accuracy_score
accuracy_score(y_test, clf_lr.predict(X_test))
# 0.88