【机器学习实战】理解Scikit-Learn中分类性能度量指标

简介: 本文是数据科学家Andrew Long撰写的技术博文,介绍了在分类模型中需要用到的度量标准以及对应Python中Scikit-Learn库实战。本文就举例介绍了分类任务中的其他度量标准,首先介绍一些相关概念:精确度、召回率、F1分数、TRP和FPR等。

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 pd
df = pd.read_csv('data.csv')
df.head()

image

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

thresh = 0.5
df['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

这四个部分可以用以下图像表示,我们将在下面的许多计算中用到此图像。引用自:
https://en.wikipedia.org/wiki/Precision_and_recall#/media/File:Precisionrecall.svg

image

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

image

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

from sklearn.metrics importconfusion_matrix
confusion_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 here
def find_FP(y_true, y_pred):
    # countsthe number of false positives (y_true = 0, y_pred = 1)
   return # your code here
def 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 np
def 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,TN
def 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_score
accuracy_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 here
assertmy_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_score
recall_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 here
assert 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_score
precision_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 here
assert 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_score
f1_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 here
assert 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_curve
fpr_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 asplt
plt.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_score
auc_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 asplt
plt.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
本文来自云栖社区合作伙伴“专知”,了解相关信息可以关注“专知

相关文章
|
21天前
|
机器学习/深度学习 人工智能 自然语言处理
机器学习之线性回归与逻辑回归【完整房价预测和鸢尾花分类代码解释】
机器学习之线性回归与逻辑回归【完整房价预测和鸢尾花分类代码解释】
|
1月前
|
机器学习/深度学习 数据可视化 算法
机器学习中的分类问题:如何选择和理解性能衡量标准
机器学习中的分类问题:如何选择和理解性能衡量标准
机器学习中的分类问题:如何选择和理解性能衡量标准
|
1月前
|
机器学习/深度学习 自然语言处理 算法
机器学习-特征选择:如何用信息增益提升模型性能?
机器学习-特征选择:如何用信息增益提升模型性能?
51 1
|
7天前
|
机器学习/深度学习 算法 数据处理
构建自定义机器学习模型:Scikit-learn的高级应用
【4月更文挑战第17天】本文探讨了如何利用Scikit-learn构建自定义机器学习模型,包括创建自定义估计器、使用管道集成数据处理和模型、深化特征工程以及调优与评估模型。通过继承`BaseEstimator`和相关Mixin类,用户可实现自定义算法。管道允许串联多个步骤,而特征工程涉及多项式特征和自定义变换。模型调优可借助交叉验证和参数搜索工具。掌握这些高级技巧能提升机器学习项目的效果和效率。
|
16天前
|
机器学习/深度学习 人工智能 算法
机器学习基础:使用Python和Scikit-learn入门
【4月更文挑战第9天】本文介绍了使用Python和Scikit-learn进行机器学习的基础知识和入门实践。首先,简述了机器学习的基本概念和类型。接着,展示了如何安装Python和Scikit-learn,加载与处理数据,选择模型进行训练,以及评估模型性能。通过本文,读者可了解机器学习入门步骤,并借助Python和Scikit-learn开始实践。
|
17天前
|
机器学习/深度学习 数据采集 算法
机器学习实战第3天:手写数字识别
机器学习实战第3天:手写数字识别
22 0
|
1月前
|
机器学习/深度学习 算法
机器学习的魔法(二)超越预测的界限-揭秘机器学习的黑科技-探索监督学习中的回归和分类问题
机器学习的魔法(二)超越预测的界限-揭秘机器学习的黑科技-探索监督学习中的回归和分类问题
131 0
|
1月前
|
机器学习/深度学习 算法
机器学习与深度学习的算法分类
机器学习与深度学习的算法分类
|
1月前
|
人工智能 前端开发 PyTorch
AI加速引擎PAI-TorchAcc:整体介绍与性能概述
PAI-TorchAcc(Torch Accelerator)是阿里云人工智能平台PAI开发的Pytorch上的大模型训练加速框架。PAI-TorchAcc提供了一套基于Pytorch的简洁、易用的接口,无需进行模型转换就可以无缝地接入HuggingFace上的模型,并用多种分布式策略进行训练加速。本文详细介绍PAI-TorchAcc的产品能力与性能。
|
2月前
|
机器学习/深度学习 自然语言处理 算法
如何利用机器学习算法提高分类准确率
【2月更文挑战第7天】机器学习在现代科技中扮演着重要的角色。分类是其中一种基本的机器学习任务,而分类准确率是衡量分类模型好坏的重要指标。本文将介绍如何利用机器学习算法来提高分类准确率。
25 0

热门文章

最新文章