我使用 sklearn 来计算分类器的平均精确度和 ROC_AUC,同时使用 yellowbrick 来绘制 ROC_AUC 和精确度-召回率曲线。问题在于这两个包在两种指标上给出的分数不同,我不知道哪个是正确的。
使用的代码如下:
import numpy as npfrom sklearn.linear_model import LogisticRegressionfrom sklearn.model_selection import train_test_splitfrom yellowbrick.classifier import ROCAUCfrom yellowbrick.classifier import PrecisionRecallCurvefrom sklearn.datasets import make_classificationfrom sklearn.metrics import roc_auc_scorefrom sklearn.metrics import average_precision_scoreseed = 42# provides de dataX, 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)# visualizationsviz3 = 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 计算的值。
回答:
由于您使用了 scikit-learn 的 predict
方法,您的预测 y_pred
是硬类别成员,而不是概率值:
np.unique(y_pred)# array([0, 1])
但对于 ROC 和精确度-召回率的计算,这不应该是这样的;您传递给这些方法的预测应该是概率,而不是硬类别。从 average_precision_score
的文档中可以看到:
y_score: array, shape = [n_samples] or [n_samples, n_classes]
目标分数,可以是正类别的概率估计、置信值或非阈值决策测量值(如某些分类器的“decision_function”返回的)。
其中非阈值的含义正是不是硬类别。对于 roc_auc_score
也是如此(文档)。
通过以下代码进行修正,使 scikit-learn 的结果与 Yellowbrick 返回的结果一致:
y_pred = clf_lr.predict_proba(X_test) # 获取概率值y_prob = np.array([x[1] for x in y_pred]) # 保留正类别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.9545954595459546Average_precision: 0.9541994473779806
由于 Yellowbrick 在内部(并且透明地)处理了所有这些计算细节,因此它不会受到手动 scikit-learn 过程中犯的错误的影响。
请注意,在二元情况下(如本例),您可以(并且应该)使用 binary=True
参数使您的图表不那么杂乱:
viz3 = ROCAUC(LogisticRegression(random_state=seed), binary=True) # 同样适用于 PrecisionRecall 曲线
并且,与人们可能直观期望的相反,至少在二元情况下,ROCAUC
的 score
方法不会返回 AUC,而是返回准确率,如文档中所指定的:
viz3.score(X_test, y_test)# 0.88# 验证这是准确率:from sklearn.metrics import accuracy_scoreaccuracy_score(y_test, clf_lr.predict(X_test))# 0.88