python3 如何评价模型的表现(分类指标:confusion matrix、ROC、AUC)_normalized confusion matrix-程序员宅基地

技术标签: python  数据分析  ROC  混淆矩阵  分类  AUC  模型评价指标  

1. 错误率和准确率

准确率不是评价模型好坏的标准,如遇到类别不平衡(class imbalance)的数据,典型的垃圾邮件问题,99%的邮件都是非垃圾邮件,1%为垃圾邮件,那分类准确率99%就没有什么意义。

错误率 = 分类错误样本数/样本总数    准确率:分类正确样本数/样本总数

2. 混淆矩阵

  • 类别
 

predicted:spam email (expectation)

predicted:real email (expectation)

actual:spam email (observation)

true positive(tp) false negative(fn)

actual:real email (observation)

false positive(fp) true negative(tn)
  • 评价指标

                precision = \frac{tp}{tp+fp}           从预测的角度(查准率)

               recall = \frac{tp}{tp+fn}           从观测的角度(查全率)

               F1score =\frac{2}{\frac{1}{precision}+\frac{1}{recall}}= 2*\frac{precision*recall}{precision+recall}=\frac{2*TP}{n_{samples}+TP-TN}

补充:F1是基于查准率和查全率的调和平均(harmonic mean)定义的:   \frac{1}{F1}=\frac{1}{2}\times(\frac{1}{P}+\frac{1}{R})

调和平均数有简单调和平均数和加权调和平均数两种。这里的F1便是简单调和平均数,后面提到的F_\beta加权调和平均数

  •  指标意义:

查准率越高,说明少数真实邮件(real emails)被预测为垃圾邮件(spam emails)(fp较小);查全率越高,说明大部分垃圾邮箱被预测准确

查全率与查准率是一对矛盾的变量(如下图, P-R图)。一般,查准率高时,查全率低;查全率高时,查准率低。在应用中,对查准率和查全率重视程度有所不同。如在商品推荐系统中,为了尽可能少打扰用户,更希望推荐的内容是用户感兴趣的,此时查准率更重要;而在逃犯信息检索系统中,更希望尽可能少漏掉逃犯,此时查全率更重要;在医院诊断癌症,他既不希望跟一个没有癌症的病人说得了癌症,这样病人会压力很大而且花费很多在测试上;又不希望跟得了癌症的病人说没得癌症,这样可能会出人命有的,因此查全率和查准率都很重要。

                                                              

虽然查全率和查准率相互矛盾,但人们仍想对不同模型之间的性能进行比较,因此引入了平衡点(break event point, BEP,查全率=查准率时的取值)来综合考虑查准率和查全率,但BEP过于简单,因此常用F1度量。因为在不同的应用中,查准率和查全率的要求不一样,因此可能存在偏好(用户-查准率,罪犯-查全率),所以F1度量引入了F_\beta

                                                 F_\beta = \frac{(1+\beta ^2)*P*R}{(\beta ^2*P)+R}

 beta>0,度量了查全率对查准率的相对重要性;beta=0,标准F1;beta>1时查全率有更大影响;beta<1时查准率有更大影响。

补充:F_\beta是加权调和平均数:\frac{1}{F_\beta}=\frac{1}{1+\beta^2}\times(\frac{1}{P}+\frac{1}{R}\times \beta^2),与算数平均(\frac{P+R}{2})和几何平均(\sqrt{P+R})相比,调和平均更重视较小值。

当有多个二分类器时,如进行多次训练/测试,每次得到一个混淆矩阵;或在多个数据集上进行训练/测试,希望估计算法的全局性能;或是执行多分类任务,每两两类别组合对应一个混淆矩阵..,希望在n个二分类混淆矩阵上综合考察查准率和查全率。因此引申出了宏查准率(macro-P)/宏查全率(macro-R)/宏F1(macro-F1),微查准率(micro-P)/微查全率(micro-R)/微F1(micro-F1)

宏:先计算查准率和查全率的和再求平均值:

 

微:先计算平均值再计算查准率和查全率:     

# Import necessary modules
from sklearn import datasets
from sklearn.metrics import confusion_matrix, classification_report
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import cohen_kappa_score, accuracy_score

X, y = datasets.make_classification(n_samples=200, n_features=6, n_classes=2, random_state=42)

# Create training and test set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0)

# Instantiate a k-NN classifier: knn
knn = KNeighborsClassifier(n_neighbors=6)

# Fit the classifier to the training data
knn.fit(X_train, y_train)

# Predict the labels of the test data: y_pred
y_pred = knn.predict(X_test)

# Generate the confusion matrix and classification report

print(confusion_matrix(y_test, y_pred))
# [[34  2]
#  [ 6 38]]

print(classification_report(y_test, y_pred))
#               precision    recall  f1-score   support
#            0       0.85      0.94      0.89        36
#            1       0.95      0.86      0.90        44
#    micro avg       0.90      0.90      0.90        80
#    macro avg       0.90      0.90      0.90        80
# weighted avg       0.90      0.90      0.90        80
print(cohen_kappa_score(y_test, y_pred))  # 0.8
print(accuracy_score(y_test, y_pred))  # 0.9 =(34+38)/(34+38+2+6)


"""绘制混淆矩阵"""
import matplotlib.pyplot as plt
from sklearn.utils.multiclass import unique_labels
import numpy as np

def plot_confusion_matrix(y_true, y_pred, classes, normalize=False, title=None, cmap=plt.cm.Blues):
    """this function points and plots the confusion matrix.
    Normalization can be applied by setting 'normalize=True"""
    if not title:
        if normalize:
            title = 'Normalized confusion matirx'
        else:
            title = 'Confusion matrix, without normalization'

    # compute confusion matrix
    cm = confusion_matrix(y_true, y_pred)
    # only use lables that appear in the data
    classes = classes[unique_labels(y_true, y_pred)]
    if normalize:
        cm = cm.astype(float)/cm.sum(axis=1)[:, np.newaxis]
        print('Normalized confusion matrix')
    else:
        print('Confusion matrix, without normalization')

    print(cm)

    fig, ax = plt.subplots()
    im = ax.imshow(cm, interpolation='nearest', cmap=cmap)
    ax.figure.colorbar(im, ax=ax)
    # we want to show all ticks...
    ax.set(xticks=np.arange(cm.shape[1]), yticks=np.arange(cm.shape[0]),
           xticklabels=classes, yticklabels=classes, title=title,
           ylabel='True label', xlabel='Predicted label')

    # rotate the tick lables and set their alignment
    plt.setp(ax.get_xticklabels(), rotation=45, ha='right', rotation_mode='anchor')

    # loop over data dimensions and create text annotations
    fmt = '.2f' if normalize else 'd'
    thresh = cm.max() / 2.
    for i in range(cm.shape[0]):
        for j in range(cm.shape[1]):
            ax.text(j, i, format(cm[i, j], fmt), ha='center', va='center',
                    color='white' if cm[i, j] > thresh else 'black')
    fig.tight_layout()
    return ax

# plot non-normalized confusion matrix
plot_confusion_matrix(y_test, y_pred, classes=np.array(['A','B']), normalize=False)

# plot normalized confusion matrix
np.set_printoptions(precision=2)
plot_confusion_matrix(y_test, y_pred, classes=np.array(['A','B']), normalize=True)
plt.show()

# Confusion matrix, without normalization
# [[34  2]
#  [ 6 38]]
# Normalized confusion matrix
# [[0.94 0.06]
#  [0.14 0.86]] 

              

3. ROC曲线

  • 定义:ROC(receiver operating characteristic curve):很多模型预测样本的类别时,会产生实值或概率(0-1)预测,然后将该预测值与一个分类阈值(threshold)进行比较,大于阈值则分为正类,否则反类。这个实值或概率预测结果的好坏直接决定了模型的泛化性能。(二分类中,若阈值为0.5,则预测出的概率值大于0.5的样本为正例,反之为反类)
  • 原理:实际中,可根据概率预测结果,将测试样本排序’最可能’是正例的排在前面(概率值大,接近1),‘最不可能’是正例的排在最后面(概率值接近0)。这样,分类过程中可在这个排序中以某个‘截断点 cut point(阈值)’将样本分为两部分,前一部分(>阈值)判别为正例,后一部分(<阈值)判别为反例。在不同任务下,重视查准率,可在排序中靠前的位置进行截断;重视查全率,可在排序中靠后位置截断。ROC曲线是从根据排序质量的好坏来综合考虑模型在不同任务下(不同阈值)的期望泛化性能的好坏。
  • 指标:

        sensitivity : recall, , true positive rate (TPR = tp/(tp+fn)  )

        specificity:true negative rate(= tn / (tn + fp))

        fall out : false positive rate(FPR=fp/(fp+tn))

        miss rate: false negative rate ( = fn/(fn+tp) )

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix, classification_report
from sklearn.model_selection import train_test_split
from sklearn import datasets
from sklearn.metrics import precision_recall_curve
from sklearn.metrics import roc_curve
import matplotlib.pyplot as plt

breast_cancer = datasets.load_breast_cancer()
X = breast_cancer.data
y = breast_cancer.target

# Create training and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0)

# Create the classifier: logreg
logreg = LogisticRegression()

# Fit the classifier to the training data
logreg.fit(X_train, y_train)

# Predict the labels of the test set: y_pred
y_pred = logreg.predict(X_test)
print(confusion_matrix(y_test, y_pred))
# [[ 81   2]
#  [  5 140]]
print(classification_report(y_test, y_pred))
#               precision    recall  f1-score   support
#            0       0.94      0.98      0.96        83
#            1       0.99      0.97      0.98       145
#    micro avg       0.97      0.97      0.97       228
#    macro avg       0.96      0.97      0.97       228
# weighted avg       0.97      0.97      0.97       228

"""绘制recall, precision 关系(绘制P-R曲线图)"""
y_scores = logreg.decision_function(X_test)

precision, recall, thresholds = precision_recall_curve(y_test, y_scores, pos_label=1)
# precision:array([0.90625, 0.90566038,...,1,1]
# recall:array([1., 0.99310345,...,0.0137931 , 0.00689655, 0.])
# thresholds:array([-2.99734313, -2.88824211,...,8.30548734]

plt.plot(recall, precision)
# plt.xlim([0,1.01])
# plt.ylim([0.9,1.002])
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.title('Precision-Recall Curve')

"""绘制ROC曲线(概率), 不同阈值下的fpr,tpr"""
# Compute predicted probabilities: y_pred_prob ,返回两列,第一列代表类别0,第二列代表类别1的概率
y_pred_prob = logreg.predict_proba(X_test)[:, 1]

# Generate ROC curve values: fpr, tpr, thresholds
fpr, tpr, thresholds = roc_curve(y_test, y_pred_prob)
# fpr:array([0. , 0.  , 0. , 0.01204819, ..., 0.18072289, 0.18072289, 1.])
# tpr:array([0.  , 0.00689655, ... , 0.99310345,1.  , 1. ])
# thresholds:array([1.99975290e+00, 9.99752904e-01, ..., 4.75460460e-02, 9.49441862e-20])

# Plot ROC curve
plt.plot([0, 1], [0, 1], 'k--')
plt.plot(fpr, tpr)
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.show()

                   

4. AUC

  • 定义:the area under the receiver operating characteristic (ROC) curve( AUC or AUROC)。
  • 原理:当A模型的ROC曲线包含B模型的ROC曲线时,说明A比B好,如果A与B的曲线相交呢,如何评价?采用AUC
  • ROC曲线下的面积越大,模型性能越好(why? 看上面的ROC曲线图,假设TPR的精度最高(为1),FPR此时为0,此时ROC下的面积最大,因此可以用ROC面积表示)。
# 连着上面的代码
"""计算AUC"""
from sklearn.model_selection import cross_val_score
from sklearn.metrics import roc_auc_score

# Compute and print AUC score
print(f'AUC:{roc_auc_score(y_test, y_pred_prob)}')
# AUC:0.9936850851682593

# Compute cross-validated AUC scores: cv_auc
cv_auc = cross_val_score(logreg, X, y, scoring='roc_auc')

# Print list of AUC scores
print(f'AUC scores computed using 5-fold cross validation:{cv_auc}')
# AUC scores computed using 5-fold cross validation:[0.99195171 0.99739614 0.98655462]

 

参考:《机器学习》-周志华

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/mengjizhiyou/article/details/103061227

智能推荐

艾美捷Epigentek DNA样品的超声能量处理方案-程序员宅基地

文章浏览阅读15次。空化气泡的大小和相应的空化能量可以通过调整完全标度的振幅水平来操纵和数字控制。通过强调超声技术中的更高通量处理和防止样品污染,Epigentek EpiSonic超声仪可以轻松集成到现有的实验室工作流程中,并且特别适合与表观遗传学和下一代应用的兼容性。Epigentek的EpiSonic已成为一种有效的剪切设备,用于在染色质免疫沉淀技术中制备染色质样品,以及用于下一代测序平台的DNA文库制备。该装置的经济性及其多重样品的能力使其成为每个实验室拥有的经济高效的工具,而不仅仅是核心设施。

11、合宙Air模块Luat开发:通过http协议获取天气信息_合宙获取天气-程序员宅基地

文章浏览阅读4.2k次,点赞3次,收藏14次。目录点击这里查看所有博文  本系列博客,理论上适用于合宙的Air202、Air268、Air720x、Air720S以及最近发布的Air720U(我还没拿到样机,应该也能支持)。  先不管支不支持,如果你用的是合宙的模块,那都不妨一试,也许会有意外收获。  我使用的是Air720SL模块,如果在其他模块上不能用,那就是底层core固件暂时还没有支持,这里的代码是没有问题的。例程仅供参考!..._合宙获取天气

EasyMesh和802.11s对比-程序员宅基地

文章浏览阅读7.7k次,点赞2次,收藏41次。1 关于meshMesh的意思是网状物,以前读书的时候,在自动化领域有传感器自组网,zigbee、蓝牙等无线方式实现各个网络节点消息通信,通过各种算法,保证整个网络中所有节点信息能经过多跳最终传递到目的地,用于数据采集。十多年过去了,在无线路由器领域又把这个mesh概念翻炒了一下,各大品牌都推出了mesh路由器,大多数是3个为一组,实现在面积较大的住宅里,增强wifi覆盖范围,智能在多热点之间切换,提升上网体验。因为节点基本上在3个以内,所以mesh的算法不必太复杂,组网形式比较简单。各厂家都自定义了组_802.11s

线程的几种状态_线程状态-程序员宅基地

文章浏览阅读5.2k次,点赞8次,收藏21次。线程的几种状态_线程状态

stack的常见用法详解_stack函数用法-程序员宅基地

文章浏览阅读4.2w次,点赞124次,收藏688次。stack翻译为栈,是STL中实现的一个后进先出的容器。要使用 stack,应先添加头文件include<stack>,并在头文件下面加上“ using namespacestd;"1. stack的定义其定义的写法和其他STL容器相同, typename可以任意基本数据类型或容器:stack<typename> name;2. stack容器内元素的访问..._stack函数用法

2018.11.16javascript课上随笔(DOM)-程序员宅基地

文章浏览阅读71次。<li> <a href = "“#”>-</a></li><li>子节点:文本节点(回车),元素节点,文本节点。不同节点树:  节点(各种类型节点)childNodes:返回子节点的所有子节点的集合,包含任何类型、元素节点(元素类型节点):child。node.getAttribute(at...

随便推点

layui.extend的一点知识 第三方模块base 路径_layui extend-程序员宅基地

文章浏览阅读3.4k次。//config的设置是全局的layui.config({ base: '/res/js/' //假设这是你存放拓展模块的根目录}).extend({ //设定模块别名 mymod: 'mymod' //如果 mymod.js 是在根目录,也可以不用设定别名 ,mod1: 'admin/mod1' //相对于上述 base 目录的子目录}); //你也可以忽略 base 设定的根目录,直接在 extend 指定路径(主要:该功能为 layui 2.2.0 新增)layui.exten_layui extend

5G云计算:5G网络的分层思想_5g分层结构-程序员宅基地

文章浏览阅读3.2k次,点赞6次,收藏13次。分层思想分层思想分层思想-1分层思想-2分层思想-2OSI七层参考模型物理层和数据链路层物理层数据链路层网络层传输层会话层表示层应用层OSI七层模型的分层结构TCP/IP协议族的组成数据封装过程数据解封装过程PDU设备与层的对应关系各层通信分层思想分层思想-1在现实生活种,我们在喝牛奶时,未必了解他的生产过程,我们所接触的或许只是从超时购买牛奶。分层思想-2平时我们在网络时也未必知道数据的传输过程我们的所考虑的就是可以传就可以,不用管他时怎么传输的分层思想-2将复杂的流程分解为几个功能_5g分层结构

基于二值化图像转GCode的单向扫描实现-程序员宅基地

文章浏览阅读191次。在激光雕刻中,单向扫描(Unidirectional Scanning)是一种雕刻技术,其中激光头只在一个方向上移动,而不是来回移动。这种移动方式主要应用于通过激光逐行扫描图像表面的过程。具体而言,单向扫描的过程通常包括以下步骤:横向移动(X轴): 激光头沿X轴方向移动到图像的一侧。纵向移动(Y轴): 激光头沿Y轴方向开始逐行移动,刻蚀图像表面。这一过程是单向的,即在每一行上激光头只在一个方向上移动。返回横向移动: 一旦一行完成,激光头返回到图像的一侧,准备进行下一行的刻蚀。

算法随笔:强连通分量-程序员宅基地

文章浏览阅读577次。强连通:在有向图G中,如果两个点u和v是互相可达的,即从u出发可以到达v,从v出发也可以到达u,则成u和v是强连通的。强连通分量:如果一个有向图G不是强连通图,那么可以把它分成躲个子图,其中每个子图的内部是强连通的,而且这些子图已经扩展到最大,不能与子图外的任一点强连通,成这样的一个“极大连通”子图是G的一个强连通分量(SCC)。强连通分量的一些性质:(1)一个点必须有出度和入度,才会与其他点强连通。(2)把一个SCC从图中挖掉,不影响其他点的强连通性。_强连通分量

Django(2)|templates模板+静态资源目录static_django templates-程序员宅基地

文章浏览阅读3.9k次,点赞5次,收藏18次。在做web开发,要给用户提供一个页面,页面包括静态页面+数据,两者结合起来就是完整的可视化的页面,django的模板系统支持这种功能,首先需要写一个静态页面,然后通过python的模板语法将数据渲染上去。1.创建一个templates目录2.配置。_django templates

linux下的GPU测试软件,Ubuntu等Linux系统显卡性能测试软件 Unigine 3D-程序员宅基地

文章浏览阅读1.7k次。Ubuntu等Linux系统显卡性能测试软件 Unigine 3DUbuntu Intel显卡驱动安装,请参考:ATI和NVIDIA显卡请在软件和更新中的附加驱动中安装。 这里推荐: 运行后,F9就可评分,已测试显卡有K2000 2GB 900+分,GT330m 1GB 340+ 分,GT620 1GB 340+ 分,四代i5核显340+ 分,还有写博客的小盒子100+ 分。relaybot@re...

推荐文章

热门文章

相关标签