分类任务:从MNIST说起(三)ROC曲线


我把自己的原码放在这里了,用Jupyter notebook编写的,包含该系列的所有代码,有需要的同学请自取!!

附件点击下载

ROC曲线

ROC曲线全称:受试者工作特征曲线,用于绘制真正类率(即召回率)和假正类率(FPR)。FPR是被错误分成正类的负类实例比率。数值上等于1-真负类率(TNR)。TNR是被正确分类为负类的负类实例比率,也称为特异度。因此,ROC曲线绘制的是灵敏度(召回率)和(1-特异度)的关系。

绘制过程

要绘制ROC曲线,首先需要使用roc_curve()函数计算多种阈值的TPR和FPR。
计算方式如下:

from sklearn.metrics import roc_curve

fpr, tpr, thresholds = roc_curve(y_train_5, y_scores)    

然后使用Matplotlib绘制FPR和TPR的曲线。

def plot_roc_curve(fpr, tpr, label=None):
    plt.plot(fpr, tpr, linewidth=2, label=label)
    plt.plot([0, 1], [0, 1], 'k--') # 用于绘制虚线对角线
    plt.axis([0, 1, 0, 1])
    plt.xlabel('假正率', fontsize=16)
    plt.ylabel('真正率(召回率)', fontsize=16)
    plt.grid(True)  

plt.figure(figsize=(8, 6))
plot_roc_curve(fpr, tpr)
fpr_90 = fpr[np.argmax(tpr >= recall_90_precision)] 
plt.plot([fpr_90, fpr_90], [0., recall_90_precision], "r:")
plt.plot([0.0, fpr_90], [recall_90_precision, recall_90_precision], "r:")
plt.plot([fpr_90], [recall_90_precision], "ro") 
save_fig("roc_curve_plot")
plt.show()

图像如下:




图中的红点就是我们选定的比率,即精度$90%$的比率。

通过ROC测量分类器性能

有一种比较分类器的方法是测量去线下的面积(AUC)。完美的分类器的ROC,其AUC等于1,而纯随机分类器的ROC其AUC=0.5.Scikit-Learn提供的AUC函数如下:

from sklearn.metrics import roc_auc_score

roc_auc_score(y_train_5, y_scores)

输出:

0.9604938554008616

精度/召回率(PR)曲线与ROC曲线的选择

经验法则:

  • 正类非常少,或者分类目标更加关注假正类而不是假负类时,选择PR曲线(如儿童视频过滤)。反之选择ROC曲线。

通过ROC对比不同的而分类器

我们再训练一个随机森林,比较随机森林和SGC的ROC曲线和ROC AUC分数。
注:随机森林没有decision_function()方法,但有dict_proba()方法,用于返回一个数组,每行代表一个实例,每列代表一个类别,即:某个给定实例属于某个给定类别的概率。
另外,Scikit-Learn的分类器通常会有这两种方法的一种,或者两种都有
训练随机森林:

from sklearn.ensemble import RandomForestClassifier
forest_clf = RandomForestClassifier(n_estimators=100, random_state=42)
y_probas_forest = cross_val_predict(forest_clf, X_train, y_train_5, cv=3,
                                    method="predict_proba")

由于roc_curve()需要标签和分数,但dict-proba()函数不提供分数,而是提供类的概率,所以我们直接使用正类的概率作为分数值:

y_scores_forest = y_probas_forest[:, 1] # score = 正类概率
fpr_forest, tpr_forest, thresholds_forest = roc_curve(y_train_5,y_scores_forest)

然后绘制ROC曲线:(两条曲线绘制在一块,作为对比)

recall_for_forest = tpr_forest[np.argmax(fpr_forest >= fpr_90)]

plt.figure(figsize=(8, 6))
plt.plot(fpr, tpr, "b:", linewidth=2, label="SGD")
plot_roc_curve(fpr_forest, tpr_forest, "随机森林")
plt.plot([fpr_90, fpr_90], [0., recall_90_precision], "r:")
plt.plot([0.0, fpr_90], [recall_90_precision, recall_90_precision], "r:")
plt.plot([fpr_90], [recall_90_precision], "ro")
plt.plot([fpr_90, fpr_90], [0., recall_for_forest], "r:")
plt.plot([fpr_90], [recall_for_forest], "ro")
plt.grid(True)
plt.legend(loc="lower right", fontsize=16)
save_fig("roc_curve_comparison_plot")
plt.show()

图像如下:




由图可知,RF的ROC曲线比SGD更靠左上,所以具有更大的AUC,所以随机森林分类器优于SGD分类器。

输出RF的ROC AUC看一下:

roc_auc_score(y_train_5, y_scores_forest)

输出:

0.9983436731328145

在测试一下精度和召回率:

y_train_pred_forest = cross_val_predict(forest_clf, X_train, y_train_5, cv=3)
print('精度:',precision_score(y_train_5, y_train_pred_forest))
print('召回率:',recall_score(y_train_5, y_train_pred_forest))

输出:

精度: 0.9905083315756169
召回率: 0.8662608374838591

这两个指标都比SGD高上不少。

声明:奋斗小刘|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 分类任务:从MNIST说起(三)ROC曲线


Make Everyday Count