美文网首页
如何评价分类模型好坏

如何评价分类模型好坏

作者: David_ess | 来源:发表于2019-11-12 10:21 被阅读0次

    前言

    在上一篇文章中,我们了解了k近邻算法,也学习了KNN算法的流程,并且手动实现了python代码和封装。
    那么在得到了分类的结果之后,它的效果如何呢?预测的准不准确?

    这里我们学习一些评估分类问题常用的指标

    判断模型好坏

    训练数据集和测试数据集

    当我们训练好一个模型之后,一般是不能直接拿到生产环境中直接使用的,我们首先要考虑和评估这个模型准确度如何。但是拿到真实环境中,数据是没有标签的,我们没有办法验证,那么该这么办呢?

    既然是这样,那么我们可以将原始数据中的一部分作为训练数据,另一部分作为测试数据,训练好模型之后,使用测试数据进行验证模型的好坏。

    那么如何对原始数据进行拆分呢?
    有时候我们的数据可能是直接排序好的,这样的话,直接拆分可能会导致测试数据的类型标签形成了一定的规律,所以我们先对数据进行一个shuffle操作把数据打乱。

    如果数据集的特征和标签是在一起的,那么可以直接shuffle之后再分解成特征和标签。
    如果特征和标签不在一起,可以使用下面的两种方法解决这一问题:
    1、将X和y合并为同一个矩阵,然后对矩阵进行shuffle,之后再分解
    2、对y的索引进行乱序,根据索引确定与X的对应关系,最后再通过乱序的索引进行赋值
    (在后面的实现代码中会给出具体代码)

    得到分割好的训练集和测试集之后,就可以应用到KNN算法中去。训练集传入fit函数中进行训练,然后对测试集的特征集进行预测,得到预测的标签集。再对预测的标签集和实际测试集的标签集进行对比。可以得到预测正确的比例。

    指标1-分类准确度accuracy

    到这里我们就可以引入第一个指标的概念:accuracy(分类准确度)。上面的预测的标签集中正确的比例就是分类的准确度

    这里我们利用之前手写的KNN算法整体实现一下数据切分和训练得出分类准确度
    使用得数据集是鸢尾花数据集,特征有4个,种类有三个标签。
    代码实现:

    import numpy as np
    from sklearn import datasets
    import matplotlib.pyplot as plt
    
    import collections
    #定义一个将多维数据转为一维数据的函数
    def flatten(x):
        result = []
        for el in x:
            if isinstance(x, collections.Iterable) and not isinstance(el, str) and not isinstance(el, float):
                result.extend(flatten(el))
            else:
                result.append(el)
        return result
    
    iris = datasets.load_iris()
    
    X = iris.data
    y = iris.target
    
    # 切分训练集和测试集方法1
    # 使用concatenate函数进行拼接,因为传入的矩阵必须具有相同的形状。
    #因此需要对label进行reshape操作,reshape(-1,1)表示行数自动计算,1列。axis=1表示纵向拼接。
    tempConcat = np.concatenate((X, y.reshape(-1,1)), axis=1)
    
    # 拼接好后,直接进行乱序操作
    np.random.shuffle(tempConcat)
    # 再将shuffle后的数组使用split方法拆分
    shuffle_X,shuffle_y = np.split(tempConcat, [4], axis=1)
    # 设置划分的比例
    test_ratio = 0.2
    test_size = int(len(X) * test_ratio)
    X_train = shuffle_X[test_size:]
    y_train = shuffle_y[test_size:]
    X_test = shuffle_X[:test_size]
    y_test = shuffle_y[:test_size]
    #转化方法1 这里需要降维转化是因为我们手写的knn算法中需要这种数据格式 下面转化2方法也是同理。
    y_train = flatten(y_train)
    y_train = np.array(y_train)
    #转化2
    # y_train = y_train.tolist()
    # y_train1=[]
    # for y_ in y_train:
    #     y_train1.append(y_[0])
    # y_train1= np.array(y_train1)
    # print(y_train1)
    # # 切分训练集和测试集方法2
    # # 将x长度这么多的数,返回一个新的打乱顺序的数组,
    # #注意,数组中的元素不是原来的数据,而是混乱的索引
    # shuffle_index = np.random.permutation(len(X))
    # # 指定测试数据的比例
    # test_ratio = 0.2
    # test_size = int(len(X) * test_ratio)
    # test_index = shuffle_index[:test_size]
    # train_index = shuffle_index[test_size:]
    # X_train = X[train_index]
    # X_test = X[test_index]
    # y_train = y[train_index]
    # y_test = y[test_index]
    # print(y_train)
    %run myKnn/kNN.py
    #from myKnn.kNN import kNNClassifier
    knn_clf = kNNClassifier(k=3)
    knn_clf.fit(X_train, y_train)
    y_predict = knn_clf.predict(X_test)
    print(y_predict)
    print(np.array(flatten(y_test)))
    
    # 两个向量的比较,返回一个布尔型向量,对这个布尔向量(faluse=1,true=0)sum,
    true_sum=sum(y_predict ==np.array(flatten(y_test)))
    accuracy=true_sum/len(y_test)
    accuracy
    

    结果:

    [0. 2. 0. 1. 0. 1. 0. 2. 0. 1. 1. 1. 1. 2. 2. 1. 2. 1. 0. 2. 2. 0. 2. 2.
     0. 2. 0. 1. 2. 0.]
    [0. 2. 0. 1. 0. 1. 0. 2. 0. 1. 1. 1. 1. 2. 2. 1. 2. 1. 0. 2. 2. 0. 2. 1.
     0. 2. 0. 1. 2. 0.]
    0.9666666666666667
    

    accuracy指标定义清洗、计算方法简单,因此经常被使用。但是只使用accuracy评价分类算法,是有很大问题的。

    比如,对于一个癌症预测系统,,输入检查指标,判断是否患有癌症,预测准确度99.9%,那这个系统是好还是坏呢?

    很显然,如果癌症的发生率是0.1%,那其实不使用任何机器学习算法,只要系统预测所有人都健康,就可以达到99.9%的准确度,也就是说对于极度偏斜(Skewed Data)的数据,只使用分类准确度是不能衡量的。
    这就需要使用混淆矩阵(Confusion Matrix)做进一步分析。

    混淆矩阵

    我们来看经典的混淆矩阵图


    image.png

    针对一个二分类问题,将实例分成正类(postive)或者负类(negative)。但是实际中分类时,会出现四种情况:
    (1)真正类(True Positive , TP):被模型预测为正类的正样本
    (2)假正类(False Positive , FP):被模型预测为正类的负样本
    (3)假负类(False Negative , FN):被模型预测为负类的正样本
    (4)真负类(True Negative , TN):被模型预测为负类的负样本
    列联表如下,1代表正类,0代表负类:


    现在假设有1万人进行预测,填入混淆矩阵如下:

    对于1万个人中,有9978个人本身并没有癌症,我们的算法也判断他没有癌症;有12个人本身没有癌症,但是我们的算法却错误地预测他有癌症;有2个人确实有癌症,但我们算法预测他没有癌症;有8个人确实有癌症,而且我们也预测对了。
    因为混淆矩阵表达的信息比简单的分类准确度更全面,因此可以通过混淆矩阵得到一些有效的指标

    指标2-精准率和召回率

    根据混淆矩阵可以求得指标:

    精准率:precision = TP/(TP+FP) ,即精准率为8/(8+12)=40%。所谓的精准率是:分母为所有预测为1的个数,分子是其中预测对了的个数,即预测值为1,且预测对了的比例。
    为什么管它叫精准率呢?在有偏的数据中,我们通常更关注值为1的特征,比如“患病”,比如“有风险”。在100次结果为患病的预测,平均有40次预测是对的。即精准率为我们关注的那个事件,预测的有多准。
    召回率:recall = TP/(TP+FN),即召回率为8/(8+2)=80%。所谓召回率是:所有真实值为1的数据中,预测对了的个数。每当有100个癌症患者,算法可以成功的预测出8个 。也就是我们关注的那个事件真实的发生情况下,我们成功预测的比例是多少。
    那么为什么需要精准率和召回率呢?还是下面的这个例子,有10000个人,混淆矩阵如下:

    如果我们粗暴的认为所有人都是健康的,那算法的准确率是99.78%,但这是毫无意义的。如果算精准率则是40%,召回率是80%。

    更关注哪个呢?

    精准率(查准率):预测值为1,且预测对了的比例,即:我们关注的那个事件,预测的有多准。

    召回率(查全率):所有真实值为1的数据中,预测对了的个数,即:我们关注的那个事件真实的发生情况下,我们成功预测的比例是多少。

    有时候,对于一个算法而言,精准率和召回率没有达到同时高或者低,这时候我们需要根据场景而定来取舍依赖的指标。

    比如我们做了一个股票预测系统,未来股票是📈还是📉这样一个二分类问题。很显然“涨”才是我们关注的焦点,那么我们肯定希望:系统预测上涨的股票中,真正上涨的比例越大越好,这就是希望查准率高。那么我们是否关注查全率呢?在大盘中有太多的真实上涨股票,虽然我们漏掉了一些上升周期,但是我们没有买进,也就没有损失。但是如果查准率不高,预测上涨的结果下跌了,那就是实实在在的亏钱了。所以在这个场景中,查准率更重要。

    当然也有追求召回率的场景,在医疗领域做疾病诊断,如果召回率低,意味着本来有一个病人得病了,但是没有正确预测出来,病情就恶化了。我们希望尽可能地将所有有病的患者都预测出来,而不是在看在预测有病的样例中有多准。
    但是,在实际业务场景中,也有很多没有这么明显的选择。那么在同时需要关注精准率和召回率,如何在两个指标中取得平衡呢?在这种情况下,我们使用一种新的指标:F1 Score

    指标2-二者兼顾 F1 Score

    如果要我们综合精准率和召回率这两个指标,我们可能会想到取平均值这样的方法。F1 Score的思想也差不多:
    F1 Score 是精准率和召回率的调和平均值

    什么是调和平均值?为什么要取调和平均值?调和平均值的特点是如果二者极度不平衡,如某一个值特别高、另一个值特别低时,得到的F1 Score值也特别低;只有二者都非常高,F1才会高。这样才符合我们对精准率和召回率的衡量标准。

    指标3-ROC曲线和AUC

    在了解ROC曲线之前,先了解三个概念:分类阈值、TPR和FPR

    分类阈值

    分类阈值,即设置判断样本为正例的阈值thr

    如果某个逻辑回归模型对某封电子邮件进行预测时返回的概率为 0.9995,则表示该模型预测这封邮件非常可能是垃圾邮件。相反,在同一个逻辑回归模型中预测分数为 0.0003 的另一封电子邮件很可能不是垃圾邮件。可如果某封电子邮件的预测分数为 0.6 呢?为了将逻辑回归值映射到二元类别,您必须指定分类阈值(也称为判定阈值)。如果值高于该阈值,则表示“垃圾邮件”;如果值低于该阈值,则表示“非垃圾邮件”。人们往往会认为分类阈值应始终为 0.5,但阈值取决于具体问题,因此您必须对其进行调整。

    TPR和FPR

    借助之前的图我们看一下:


    TPR:预测为1,且预测对了的数量,占真实值为1的数据百分比。很好理解,就是召回率。
    TPR = recall = TP/(TP+FN)
    FPR:预测为1,但预测错了的数量,占真实值不为1的数据百分比。与TPR相对应,FPR除以真实值为0的这一行所有的数字和 。
    ROC曲线

    ROC曲线(Receiver Operation Characteristic Cureve),描述TPR和FPR之间的关系。x轴是FPR,y轴是TPR
    假设采用逻辑回归分类器,其给出针对每个实例为正类的概率,那么通过设定一个阈值如0.6,概率大于等于0.6的为正类,小于0.6的为负类。对应的就可以算出一组(FPR,TPR),在平面中得到对应坐标点。随着阈值的逐渐减小,越来越多的实例被划分为正类,但是这些正类中同样也掺杂着真正的负实例,即TPR和FPR会同时增大。阈值最大时,对应坐标点为(0,0),阈值最小时,对应坐标点(1,1)。
    如下面这幅图,(a)图中实线为ROC曲线,线上每个点对应一个阈值。


    我们已经知道,TPR就是所有正例中,有多少被正确地判定为正;FPR是所有负例中,有多少被错误地判定为正。 分类阈值取不同值,TPR和FPR的计算结果也不同,最理想情况下,我们希望所有正例 & 负例 都被成功预测 TPR=1,FPR=0,即 所有的正例预测值 > 所有的负例预测值,此时阈值取最小正例预测值与最大负例预测值之间的值即可。
    TPR越大越好,FPR越小越好,但这两个指标通常是矛盾的。为了增大TPR,可以预测更多的样本为正例,与此同时也增加了更多负例被误判为正例的情况。
    AUC

    一般在ROC曲线中,我们关注是曲线下面的面积, 称为AUC(Area Under Curve)。这个AUC是横轴范围(0,1 ),纵轴是(0,1)所以总面积是小于1的。
    ROC和AUC的主要应用:比较两个模型哪个好?主要通过AUC能够直观看出来。
    ROC曲线下方由梯形组成,矩形可以看成特征的梯形。因此,AUC的面积可以这样算:(上底+下底)* 高 / 2,曲线下面的面积可以由多个梯形面积叠加得到。AUC越大,分类器分类效果越好。

    AUC = 1,是完美分类器,采用这个预测模型时,不管设定什么阈值都能得出完美预测。绝大多数预测的场合,不存在完美分类器。
    0.5 < AUC < 1,优于随机猜测。这个分类器(模型)妥善设定阈值的话,能有预测价值。
    AUC = 0.5,跟随机猜测一样,模型没有预测价值。
    AUC < 0.5,比随机猜测还差;但只要总是反预测而行,就优于随机猜测。
    以下示例三种AUC值(曲线下面积)

    为什么我们使用ROC和AUC呢

    既然已经这么多评价标准,为什么还要使用ROC和AUC呢?因为ROC曲线有个很好的特性:当测试集中的正负样本的分布变化的时候,ROC曲线能够保持不变。在实际的数据集中经常会出现类不平衡(class imbalance)现象,即负样本比正样本多很多(或者相反),而且测试数据中的正负样本的分布也可能随着时间变化。

    总结

    这一节我们了解了各种评价分类模型好坏的指标,具体使用哪一种,是依据应用场景而定

    参考:https://blog.csdn.net/guohecang/article/details/52276548

    相关文章

      网友评论

          本文标题:如何评价分类模型好坏

          本文链接:https://www.haomeiwen.com/subject/mfafictx.html