分类算法的评价

作者: 抹茶不加茶 | 来源:发表于2020-03-09 18:20 被阅读0次

    准确度陷阱

    我们首先看一下这个例子

    癌症预测系统
    • 何为准确度陷阱?
      对于极度偏斜的数据,只使用分类准确度是远远不够的,我们很容易完全没法判断算法的好坏。

    混淆矩阵(二分类问题)

    二分类

    精准率和召回率

    • 精准率:预测为真的情况下预测正确的概率
      (例如在癌症预测系统中,精准率就代表了预测癌症预测的成功率)


      精准率
    • 召回率:真实发生我数据中我们成功预测的概率
      (例如在癌症预测系统中,召回率代表患癌症总人数中我们通过算法预测成功的概率)
      召回率
      现在我们回到开头的那个问题,我们使用精准率和召回率进行分析
      对比
      我们意识到准确率没法判断的作用,而精准率和召回率可以用来判断
      下面进行代码实现
    import numpy as np
    from sklearn import datasets
    digits=datasets.load_digits()
    x=digits.data
    y=digits.target.copy()
    y[digits.target==9]=1
    y[digits.target!=9]=0#构造出一个极度偏斜的数据
    from sklearn.model_selection import train_test_split
    x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.2,random_state=666)
    #实际上这里size默认是0.2
    from sklearn.linear_model import LogisticRegression 
    log_reg=LogisticRegression()
    log_reg.fit(x_train,y_train)
    log_reg.score(x_test,y_test)
    

    这里我们发现准确度很高,实际上全部判断为0也会很高


    高准确度
    y_log_predict=log_reg.predict(x_test)
    def TN(y_true,y_predict):
        return np.sum((y_true==0)&(y_predict==0))
    def FP(y_true,y_predict):
        return np.sum((y_true==0)&(y_predict==1))
    def FN(y_true,y_predict):
        return np.sum((y_true==1)&(y_predict==0))
    def TP(y_true,y_predict):
        return np.sum((y_true==1)&(y_predict==1))
    def confusion_matrix(y_true,y_predict):
        return np.array([
            [TN(y_true,y_predict),FP(y_true,y_predict)],
            [FN(y_true,y_predict),TP(y_true,y_predict)]
        ])
    

    我们可以看到混淆矩阵


    混淆矩阵
    def precesion_score(y_true,y_predict):
        tp=TP(y_true,y_predict)
        fp=FP(y_true,y_predict)
        try:
            return tp/(tp+fp)#异常检测,正如前面的例子,唯一的异常便是分母为零的情况
        except:
            return 0
    def recall_score(y_true,y_predict):
        tp=TP(y_true,y_predict)
        fn=FN(y_true,y_predict)
        try:
            return tp/(tp+fn)
        except:
            return 0
    

    我们分别可以得到其精准率和召回率


    精准率
    召回率
    利用sklearn中的函数实现
    #sklearn中的
    from sklearn.metrics import confusion_matrix
    confusion_matrix(y_test,y_log_predict)
    from sklearn.metrics import precision_score
    precesion_score(y_test,y_log_predict)
    from sklearn.metrics import recall_score
    recall_score(y_test,y_log_predict)
    

    我们也可以得到相同的答案


    sklearn实现

    指标的选择

    我们同时拥有精准率和召回率两个指标,那么我们依据哪一个去判断呢?

    • 有时候我们会注重精准率,如股票预测,我们更加关系预测的数据中正确的概率
    • 有时候我们会注重召回率,如病人诊断,我们更加关心实际数据中成功预测概率
    • 二者兼顾:F1 Score,是二者的调和平均值


      F1 Score

      对前面的代码进行一次总结同时使用F1Score

    def f1_score(precesion,recall):
        try:
            return 2*precesion*recall/(precesion+recall)
        except:
            return 0
    import numpy as np
    from sklearn import datasets
    digits=datasets.load_digits()
    x=digits.data
    y=digits.target.copy()
    y[digits.target==9]=1
    y[digits.target!=9]=0#构造出一个极度偏斜的数据
    from sklearn.model_selection import train_test_split
    x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.2,random_state=666)
    #实际上这里size默认是0.2
    from sklearn.linear_model import LogisticRegression 
    log_reg=LogisticRegression()
    log_reg.fit(x_train,y_train)
    y_log_predict=log_reg.predict(x_test)
    from sklearn.metrics import confusion_matrix
    confusion_matrix(y_test,y_log_predict)
    from sklearn.metrics import precision_score
    precesion_score(y_test,y_log_predict)
    from sklearn.metrics import recall_score
    recall_score(y_test,y_log_predict)
    from sklearn.metrics import f1_score
    f1_score(y_test,y_log_predict)
    
    • 我们实际中会发现精准率和召回率之间互相矛盾,不可能同时较高,这时我们要做出取舍选择。
    • 我们回顾一下逻辑回归中的决策边界,我们可以通过改变常数项来移动这根线


      决策边界
      移动

      如图,改变常数(即阈值)我们会相应的改变精准率和召回率
      下面我们在前述代码中继续实现这个部分

    decision_scores=log_reg.decision_function(x_test)#返回一个向量,元素为score值
    y_predict2=np.array(decision_scores>=5,dtype='int')#这里选定阈值为5,之前阈值为0
    confusion_matrix(y_test,y_predict2)
    precision_score(y_test,y_predict2)
    recall_score(y_test,y_predict2)
    

    我们可以看到,精准率上升而召回率下降


    阈值为5

    我们将阈值改为-5,可以看到,精确率下降而召回率上升

    y_predict3=np.array(decision_scores>=-5,dtype='int')
    confusion_matrix(y_test,y_predict3)
    precision_score(y_test,y_predict3)
    recall_score(y_test,y_predict3)
    
    阈值-5

    这也再次说明了,这两者是相互制约的,一者上升一者下降,不会出现理想的两者都上升的理想局面。
    可以通过可视化的方式来看到这一特性


    精确率和召回率

    我们也可以使用sklearn找到Precesion-Recall曲线

    from sklearn.metrics import precision_recall_curve
    precesions,recalls,thresholds=precision_recall_curve(y_test,decision_scores)
    precesions.shape
    recalls.shape
    thresholds.shape#少一个元素
    import matplotlib.pyplot as plt
    plt.plot(thresholds,precesions[:-1])#去掉一个值
    plt.plot(thresholds,recalls[:-1])
    plt.show
    plt.plot(precesions,recalls)
    plt.show
    

    对应于代码我们有如下结果


    向量大小
    曲线1
    曲线2

    ROC曲线——描述TPR和FPR之间的关系

    • TPR=Recall(True Positive Rate)
    • FPR(False Positive Rate)


      TPR&FPR

      两者同时增加减少
      这里仅使用sklearn演示roc

    from sklearn.metrics import roc_curve
    fprs,tprs,thresholds = roc_curve(y_test,decision_scores)
    plt.plot(fprs,tprs)
    plt.show
    
    FTP、TPR

    我们意识到面积可以作为指标(面积最大为1)

    from sklearn.metrics import roc_auc_score
    roc_auc_score(y_test,decision_scores)
    

    ROC可以用于比较模型的优劣,我们会选面积更大的模型

    相关文章

      网友评论

        本文标题:分类算法的评价

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