Scikit-learn и Yellowbrick дают разные оценки

Nov 02 2020

Я использую sklearn для вычисления средней точности и roc_auc классификатора и yellowbrick для построения кривых roc_auc и точности-отзыва. Проблема в том, что пакеты дают разные оценки по обоим показателям, и я не знаю, какой из них правильный.

Используемый код:

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

Код дает следующий результат:

Как видно выше, метрики дают разные значения в зависимости от пакета. В операторе печати представлены значения, вычисленные scikit-learn, тогда как на графиках отображаются аннотированные значения, вычисленные yellowbrick.

Ответы

1 desertnaut Nov 03 2020 at 05:29

Поскольку вы используете predictметод scikit-learn, ваши прогнозы y_predявляются жесткими классами, а не вероятностями:

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

Но для расчетов ROC и Precision-Recall этого не должно быть; прогнозы, которые вы передаете этим методам, должны быть вероятностями, а не жесткими классами. Из average_precision_score документов :

y_score: массив, форма = [n_samples] или [n_samples, n_classes]

Целевые баллы могут быть либо оценками вероятности положительного класса, либо значениями достоверности, либо показателем решений без пороговых значений (возвращаемым функцией «solution_function» для некоторых классификаторов).

где без пороговых значений означает именно не жесткие классы . То же самое и с roc_auc_score( docs ).

Исправление этого с помощью следующего кода делает результаты scikit-learn идентичными тем, которые возвращает 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}")

Результаты:

ROC_AUC: 0.9545954595459546
Average_precision: 0.9541994473779806

Поскольку Yellowbrick обрабатывает все эти вычислительные детали внутренне (и прозрачно), он не страдает от ошибки в ручной процедуре scikit-learn, сделанной здесь.


Обратите внимание, что в двоичном случае (как здесь) вы можете (и должны) сделать свои графики менее загроможденными binary=Trueаргументом:

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

и что, вопреки тому , что один migh ожидать интуитивно, для бинарного случая по крайней мере, scoreметод ROCAUCбудет не возвращать АУК, но точности, как указано в документации :

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