博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【机器学习实战】理解Scikit-Learn中分类性能度量指标
阅读量:6169 次
发布时间:2019-06-21

本文共 10705 字,大约阅读时间需要 35 分钟。

image

Understanding Data Science Classification Metrics in Scikit-Learn in Python

在本教程中,我们将介绍Python的scikit-learn中的一些分类度量指标 - 从头开始学习和编写我们自己的函数,以理解其中一些函数背后的数学知识。

数据科学中预测建模的一个主要领域是分类。分类就是试图预测一个群体中某一特定样本来自哪个类别。例如,如果我们试图预测某个病人是否会再次住院,可能的两类是住院(正)和非住院(负)。然后,分类模型试图预测每个患者是否将住院或未住院。换句话说,分类只是试图简单地预测人群中某一特定样本应该被放在哪个桶中(预测是正的还是预测是负的),如下所示。

image

在训练分类预测模型时,你需要评估它的好坏程度。有趣的是,有很多不同的方法来评估性能。大多数使用Python进行预测建模的数据科学家都使用名为scikit-learn的Python库。 Scikit-learn包含许多用于分析模型性能的内置函数。在本教程中,我们将介绍其中的一些指标,并从头开始编写我们自己的函数,以理解其中一些指标背后的数学原理。

本教程将介绍sklearn.metrics中的以下指标:

confusion_matrix
accuracy_score
recall_score
precision_score
f1_score
roc_curve
roc_auc_score

让我们开始吧

我们将从头开始编写自己的函数,现在假设有两个类别。请注意,您需要标记为#your code here的地方填写您自己的部分。

让我们加载一个样本数据集,其中包含两个模型(model_RF 和 model_LR)的真实标签(actual_label)和预测概率。这里的概率是第1类的概率。

import pandas as pddf = pd.read_csv('data.csv')df.head()

image

在大多数数据科学项目中,您需要定义一个阈值,以定义哪些预测概率被标记为预测正值,哪些预测概率被标记为预测负值。现在让我们假设阈值是0.5。让我们再添加另外两列,将概率转换为预测标签。

thresh = 0.5df['predicted_RF'] = (df.model_RF >=0.5).astype('int')df['predicted_LR'] = (df.model_LR >=0.5).astype('int')df.head()

image

confusion_matrix

给定一个实际的标签和一个预测的标签,我们能做的第一件事就是把样本分成4个部分:

True positive(真阳性) — 真实值(actual) = 1, 预测值(predicted) = 1
False positive(假阳性) — 真实值(actual) = 0, 预测值(predicted) = 1
False negative(假阴性) — 真实值(actual) = 1, 预测值(predicted) = 0
True negative(真阴性) — 真实值(actual) = 0, 预测值(predicted) = 0

这四个部分可以用以下图像表示,我们将在下面的许多计算中用到此图像。引用自:

image

这四个部分还可以使用混淆矩阵表示,如下所示:

image

我们可以从scikit-learn获得混淆矩阵(作为一个2x2数组),它将实际标签和预测标签作为输入:

from sklearn.metrics importconfusion_matrixconfusion_matrix(df.actual_label.values,df.predicted_RF.values)

image

其中有5047个 true positive,2360个false positive,2832个false negative和5519个true negative。让我们定义自己的函数来验证confusion_matrix。请注意,我的代码只写了第一个,你需要自己来写其他3个。

def find_TP(y_true, y_pred):    #counts the number of true positives (y_true = 1, y_pred = 1)   return sum((y_true == 1) & (y_pred == 1))def find_FN(y_true, y_pred):    #counts the number of false negatives (y_true = 1, y_pred = 0)   return # your code heredef find_FP(y_true, y_pred):    # countsthe number of false positives (y_true = 0, y_pred = 1)   return # your code heredef find_TN(y_true, y_pred):    #counts the number of true negatives (y_true = 0, y_pred = 0)   return # your code here

您可以检查您的结果是否匹配:

print('TP:',find_TP(df.actual_label.values,df.predicted_RF.values))print('FN:',find_FN(df.actual_label.values,df.predicted_RF.values))print('FP:',find_FP(df.actual_label.values,df.predicted_RF.values))print('TN:',find_TN(df.actual_label.values,df.predicted_RF.values))

让我们写一个函数,它将为我们计算所有这四个,以及另一个函数来复制confusion_matrix:

import numpy as npdef find_conf_matrix_values(y_true,y_pred):    #calculate TP, FN, FP, TN    TP =find_TP(y_true,y_pred)    FN =find_FN(y_true,y_pred)    FP =find_FP(y_true,y_pred)    TN =find_TN(y_true,y_pred)   return TP,FN,FP,TNdef my_confusion_matrix(y_true, y_pred):   TP,FN,FP,TN = find_conf_matrix_values(y_true,y_pred)   return np.array([[TN,FP],[FN,TP]])

检查您的结果是否匹配:

my_confusion_matrix(df.actual_label.values,df.predicted_RF.values)

与其手工比较,不如使用Python内置的assert和numpy的array_equal函数来验证我们的函数是否有效:

assert np.array_equal(my_confusion_matrix(df.actual_label.values,df.predicted_RF.values), confusion_matrix(df.actual_label.values,df.predicted_RF.values) ), 'my_confusion_matrix() is not correct for RF'assert np.array_equal(my_confusion_matrix(df.actual_label.values,df.predicted_LR.values),confusion_matrix(df.actual_label.values,df.predicted_LR.values) ), 'my_confusion_matrix() is not correct for LR'

给定了这四个部分(TP、FP、FN、TN),我们可以计算许多其他性能指标。

accuracy_score

最常用的分类度量指标就是准确性,即正确预测的样本的分数,如下图所示:

image

我们可以从scikit-learn获得accuracy score,它以实际标签和预测标签作为输入:

from sklearn.metrics importaccuracy_scoreaccuracy_score(df.actual_label.values,df.predicted_RF.values)

您的结果应该是 0.6705165630156111

复制accuracy_score来定义您自己的函数,使用上面的公式。

def my_accuracy_score(y_true,y_pred):    #calculates the fraction of samples predicted correctly   TP,FN,FP,TN = find_conf_matrix_values(y_true,y_pred)     return # your code hereassertmy_accuracy_score(df.actual_label.values, df.predicted_RF.values)    ==accuracy_score(df.actual_label.values, df.predicted_RF.values),'my_accuracy_score failed on RF'assertmy_accuracy_score(df.actual_label.values, df.predicted_LR.values)    ==accuracy_score(df.actual_label.values, df.predicted_LR.values),'my_accuracy_score failed on LR'print('Accuracy RF:%.3f'%(my_accuracy_score(df.actual_label.values, df.predicted_RF.values)))print('Accuracy LR:%.3f'%(my_accuracy_score(df.actual_label.values, df.predicted_LR.values)))

使用accuracy作为性能指标,RF模型(0.67)比LR模型(0.62)准确率更高。那么我们应该说RF模型是最好的模型吗?不!准确性(Accuracy)并不总是用于评估分类模型的最佳指标。例如,假设我们要预测的是100次中只有1次发生的事情。我们可以建立一个模型,说这个事件从来没有发生过,从而获得99%的准确率。然而,我们真正关心的事件却获得了0%的正确率。其实,这里的0%是另一个性能度量,称为recall(召回率)。

recall_score

Recall召回率是您正确预测的positive事件的分数,如下所示:

image

我们可以从scikit-learn获得recall score,它以实际标签和预测标签作为输入:

from sklearn.metrics importrecall_scorerecall_score(df.actual_label.values,df.predicted_RF.values)

复制recall_score来定义您自己的函数,使用上面的公式。

def my_recall_score(y_true,y_pred):    #calculates the fraction of positive samples predicted correctly   TP,FN,FP,TN = find_conf_matrix_values(y_true,y_pred)     return # your code hereassert my_recall_score(df.actual_label.values,df.predicted_RF.values)    == recall_score(df.actual_label.values,df.predicted_RF.values), 'my_accuracy_score failed on RF'assert my_recall_score(df.actual_label.values,df.predicted_LR.values)    == recall_score(df.actual_label.values,df.predicted_LR.values), 'my_accuracy_score failed on LR'print('Recall RF:%.3f'%(my_recall_score(df.actual_label.values, df.predicted_RF.values)))print('Recall LR:%.3f'%(my_recall_score(df.actual_label.values, df.predicted_LR.values)))

提高召回率的一种方法是通过降低predicted positive的阈值来增加predictedpositive的样本数。但是,这也会增加false positive的数量。另一个称为精确度(precision)的性能指标考虑到了这一点。

precision_score

Precision(精确度)是实际为正的事件所占总的预测阳性事件的比,如下所示:

image

我们可以从scikit-learn获得precision score,它以实际标签和预测标签作为输入:

from sklearn.metrics importprecision_scoreprecision_score(df.actual_label.values,df.predicted_RF.values)

复制precision_score来定义您自己的函数,使用上面的公式。

def my_precision_score(y_true, y_pred):    #calculates the fraction of predicted positives samples that are actuallypositive   TP,FN,FP,TN = find_conf_matrix_values(y_true,y_pred)     return # your code hereassert my_precision_score(df.actual_label.values,df.predicted_RF.values) == precision_score(df.actual_label.values,df.predicted_RF.values), 'my_accuracy_score failed on RF'assertmy_precision_score(df.actual_label.values, df.predicted_LR.values) ==precision_score(df.actual_label.values, df.predicted_LR.values),'my_accuracy_score failed on LR'print('Precision RF:%.3f'%(my_precision_score(df.actual_label.values, df.predicted_RF.values)))print('Precision LR:%.3f'%(my_precision_score(df.actual_label.values, df.predicted_LR.values)))

在这种情况下,看起来RF模型在召回率和精确度方面都更好。但如果一个模型在召回率上更好,另一个在精度上更好,你会怎么做?一些数据科学家使用的方法称为F1 score。

f1_score

f1 score是召回率和精确度的调和平均值,得分越高越好。f1 score的计算公式如下:

image

我们可以从scikit-learn获得f1 score,它以实际标签和预测标签作为输入:

from sklearn.metrics importf1_scoref1_score(df.actual_label.values,df.predicted_RF.values)

复制f1_score来定义您自己的函数,使用上面的公式。

def my_f1_score(y_true,y_pred):    #calculates the F1 score   recall = my_recall_score(y_true,y_pred)    precision = my_precision_score(y_true,y_pred)      return# your code hereassert my_f1_score(df.actual_label.values,df.predicted_RF.values) ==     f1_score(df.actual_label.values,df.predicted_RF.values), 'my_accuracy_score failed on RF'assert my_f1_score(df.actual_label.values,df.predicted_LR.values) ==     f1_score(df.actual_label.values,df.predicted_LR.values), 'my_accuracy_score failed on LR'print('F1 RF:%.3f'%(my_f1_score(df.actual_label.values, df.predicted_RF.values)))print('F1 LR:%.3f'%(my_f1_score(df.actual_label.values, df.predicted_LR.values)))

到目前为止,我们假设我们定义了0.5的阈值,用于选择哪些样本被预测为正样本。如果我们更改此阈值,性能指标将会发生变化。如下所示:

print('scores with threshold= 0.5')print('Accuracy RF:%.3f'%(my_accuracy_score(df.actual_label.values, df.predicted_RF.values)))print('Recall RF:%.3f'%(my_recall_score(df.actual_label.values, df.predicted_RF.values)))print('Precision RF:%.3f'%(my_precision_score(df.actual_label.values, df.predicted_RF.values)))print('F1 RF:%.3f'%(my_f1_score(df.actual_label.values, df.predicted_RF.values)))print(' ')print('scores with threshold = 0.25')print('Accuracy RF:%.3f'%(my_accuracy_score(df.actual_label.values, (df.model_RF >=0.25).astype('int').values)))print('Recall RF:%.3f'%(my_recall_score(df.actual_label.values, (df.model_RF >=0.25).astype('int').values)))print('Precision RF: %.3f'%(my_precision_score(df.actual_label.values,(df.model_RF >= 0.25).astype('int').values)))print('F1 RF:%.3f'%(my_f1_score(df.actual_label.values, (df.model_RF >=0.25).astype('int').values)))

image

如果我们最初没有选择一个阈值,我们如何评估模型?一种非常常见的方法是使用ROC曲线。

roc_curve 和 roc_auc_score

ROC曲线非常有助于理解真阳性率(true-positive rate)和假阳性率(false positive rates)之间的平衡。 Scikit learn为实现和分析ROC曲线构建了函数。这些函数的输入(roc_curve和roc_auc_score)是实际标签和预测概率(不是预测标签)。

roc_curve和roc_auc_score都是复杂的函数,所以我们不会让你从头开始编写这些函数。相反,我们将向您展示如何使用scikit learn中的函数来实现并解释关键点。让我们先用roc_curve来做ROC图。

from sklearn.metrics importroc_curvefpr_RF, tpr_RF, thresholds_RF =roc_curve(df.actual_label.values, df.model_RF.values)fpr_LR, tpr_LR, thresholds_LR =roc_curve(df.actual_label.values, df.model_LR.values)

roc_curve函数返回三个列表:

thresholds = 按降序排列的所有唯一预测概率

fpr = 每个阈值的假阳性率(FP/ (FP + TN))
tpr = 每个阈值的真阳性率(TP/ (TP + FN))

image

我们可以绘制每个模型的ROC曲线,如下所示。

import matplotlib.pyplot aspltplt.plot(fpr_RF, tpr_RF,'r-',label = 'RF')plt.plot(fpr_LR,tpr_LR,'b-', label= 'LR')plt.plot([0,1],[0,1],'k-',label='random')plt.plot([0,0,1,1],[0,1,1,1],'g-',label='perfect')plt.legend()plt.xlabel('False Positive Rate')plt.ylabel('True Positive Rate')plt.show()

image

我们可以从这个图中得到一些结论:

一个随机猜测标签的模型应该如黑色的线所表示的那样,你想要一个在黑线之上有一条曲线的模型

距离黑线较远的ROC更好,因此RF(红色)看起来比LR(蓝色)好

虽然没有直接看到,但是高阈值会产生左下角的点,低阈值产生了右上角的点。这意味着当您降低阈值时,您将获得更高的TPR,但代价是更高的FPR

为了分析性能,我们将使用area-under-curve(曲线下面积)这一度量指标.

from sklearn.metrics importroc_auc_scoreauc_RF = roc_auc_score(df.actual_label.values,df.model_RF.values)auc_LR = roc_auc_score(df.actual_label.values,df.model_LR.values)print('AUC RF:%.3f'% auc_RF)print('AUC LR:%.3f'% auc_LR)

如您所见,RF模型的曲线下面积(AUC = 0.738)优于LR(AUC = 0.666)。当我绘制ROC曲线时,我喜欢在图例中添加AUC,如下所示。

import matplotlib.pyplot aspltplt.plot(fpr_RF, tpr_RF,'r-',label = 'RF AUC:%.3f'%auc_RF)plt.plot(fpr_LR,tpr_LR,'b-', label= 'LR AUC:%.3f'%auc_LR)plt.plot([0,1],[0,1],'k-',label='random')plt.plot([0,0,1,1],[0,1,1,1],'g-',label='perfect')plt.legend()plt.xlabel('False Positive Rate')plt.ylabel('True Positive Rate')plt.show()

image

总的来说,在这个示例中,模型RF在每个性能指标上都是获胜的。

总结

在预测分析中,当在两个模型之间做决定时,选择单个性能指标非常重要。正如您在此处所看到的,您可以选择许多(准确度,召回率,精确度,f1-score,AUC等等)。最终,您应该使用最适合当前业务问题的性能度量。许多数据科学家更喜欢使用AUC来分析每个模型的性能,因为它不需要选择阈值并有助于平衡真阳性率(true positive rate)和假阳性率(false positiverate)。

原文发布时间为:2018-08-07

本文作者:Andrew Long
本文来自云栖社区合作伙伴“”,了解相关信息可以关注“”

转载地址:http://bjnba.baihongyu.com/

你可能感兴趣的文章
RPC框架的可靠性设计
查看>>
英特尔中国研究院院长宋继强:摩尔定律的经济效益仍在继续
查看>>
Vue2.0 Transition常见用法全解惑
查看>>
桌面上的Flutter:Electron又多了个对手
查看>>
HTTP/2推送之难,远超想象
查看>>
百度研究院今日再升级,迎来9位世界级科学家
查看>>
微软开源PDB
查看>>
微软Azure容器服务要关停,你想好怎么迁移了吗?
查看>>
微软宣布支持基于虚拟机的Azure IOT Edge服务
查看>>
高性能的网页开发概要
查看>>
JUnit 5 – 早期试用体验 – 第1篇
查看>>
彻底与高通谈崩?苹果被爆计划自研5G调制解调器
查看>>
代码自解释不是不写注释的理由
查看>>
使用 mock.js 让前端开发与后端独立
查看>>
(翻译) MongoDB(19) mongo Shell
查看>>
[小工具] 微信小程序代码压缩器
查看>>
「前端开发者」如何把握住「微信小程序」这波红利?
查看>>
「译」JUnit 5 系列:扩展模型(Extension Model)
查看>>
ios开发之通讯录
查看>>
Mac IntelliJ IDEA 使用 Subversion 问题解决记录
查看>>