机器学习:逻辑回归之混淆矩阵、精度、召回、F1-score、ROC曲线、AUC指标分析

1、肿瘤预测案例

数据描述

(1)699条样本,共11列数据,第一列用语检索的id,后9列分别是与肿瘤

相关的医学特征,最后一列表示肿瘤类型的数值。

(2)包含16个缺失值,用”?”标出。

(3)2 表示良性、4 表示恶性

代码:

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression


if __name__ == "__main__":

    names = ['Sample code number',
             'Clump Thickness',
             'Uniformity of Cell Size',
             'Uniformity of Cell Shape',
             'Marginal Adhesion',
             'Single Epithelial Cell Size',
             'Bare Nuclei',
             'Bland Chromatin',
             'Normal Nucleoli',
             'Mitoses',
             'Class']
    # 读取数据
    data = pd.read_csv("./data/breast-cancer-wisconsin.data", names=names)

    # 缺失值处理
    data = data.replace(to_replace="?", value=np.nan)
    data = data.dropna()

    # 确定特征值、目标值
    x = data.iloc[:, 1:-1]
    y = data["Class"]

    # 分割数据集
    x_train, x_test, y_train, y_test = \
        train_test_split(x, y, random_state=5, test_size=0.2)

    # 标准化
    transfer = StandardScaler()
    x_train = transfer.fit_transform(x_train)
    x_test = transfer.fit_transform(x_test)

    # 模型训练
    estimator = LogisticRegression()
    estimator.fit(x_train, y_train)

    # 预测评估
    # estimator.classes_[1] 当做正类(1类)
		# estimator.classes_
    y_pred = estimator.predict(x_test)
    print("预测结果:\n", y_pred)

    accuracy = estimator.score(x_test, y_test)
    print("准确率是:\n", accuracy)

输出结果:

预测结果:
 [2 2 2 2 4 4 2 2 4 4 2 2 2 2 2 4 2 2 2 2 4 4 4 2 2 2 2 4 2 4 2 4 2 4 2 2 4
 2 4 2 2 2 2 2 2 4 2 4 4 2 2 2 4 2 2 2 2 4 4 2 2 2 2 2 2 4 2 4 2 2 2 4 4 2
 4 4 4 2 4 4 2 2 4 2 2 2 2 4 4 4 2 2 2 2 2 2 2 2 4 2 2 2 4 2 2 2 2 2 4 4 2
 4 4 2 2 2 4 2 4 4 4 2 2 2 4 2 2 2 2 2 4 2 4 2 2 2 2]
准确率是:
 0.9927007299270073

2、分类评估方法介绍

在《癌症分类预测》案例中,我们通过 score 函数可以得到模型预测的准确率为 99%。这是一个很简单的指标,但是这个指标并不能满足我们对某些场景下对模型的评估。例如:我们希望模型能够把所有的恶性肿瘤预测出来,因为这关系到人的生死大事。

假设:样本中有 6 个恶性肿瘤样本,4 个良性肿瘤样本。

模型 A:预测对了 5 个恶性肿瘤样本,4 个良性肿瘤样本,其准确率为:90%

模型 B:预测对了 6 个恶性肿瘤样本,3 个良性肿瘤样本,其准确率为:90%

但是,模型 B 把所有潜在的恶性肿瘤患者全部预测出来,模型 A 只能把 5/6 的恶性肿瘤患者预测出来,哪一个模型对于当前问题场景更好呢?显然是前者。

所以,对于分类效果的评估只使用准确率去衡量并不能适应所有场景。所以,我们需要引入其他的模型评估指标。

2.1 混淆矩阵

想要获得更加精细的分类评估指标,我们得将预测结果进行更为精细的划分,这就是混淆矩阵。
在这里插入图片描述
混淆矩阵作用就是看一看在测试集样本集中:

  1. 真实值是 正例 的样本中,被分类为 正例 的样本数量有多少,这部分样本叫做真正例(TP,True Positive)
  2. 真实值是 正例 的样本中,被分类为 假例 的样本数量有多少,这部分样本叫做伪反例(FN,False Negative)
  3. 真实值是 假例 的样本中,被分类为 正例 的样本数量有多少,这部分样本叫做伪正例(FP,False Positive)
  4. 真实值是 假例 的样本中,被分类为 假例 的样本数量有多少,这部分样本叫做真反例(TN,True Negative)

True Positive :表示样本真实的类别

Positive :表示样本被预测为的类别

例子:
样本集中有 6 个恶性肿瘤样本,4 个良性肿瘤样本,我们假设恶性肿瘤为正例,则:

  1. 模型 A:预测对了 3 个恶性肿瘤样本,4 个良性肿瘤样本

    1. 真正例 TP 为:3
    2. 伪反例 FN 为:3
    3. 伪正例 FP 为:0
    4. 真反例 TN:4
  2. 模型 B:预测对了 6 个恶性肿瘤样本,1个良性肿瘤样本

    1. 真正例 TP 为:6
    2. 伪反例 FN 为:0
    3. 伪正例 FP 为:3
    4. 真反例 TN:1

我们会发现:TP+FN+FP+TN = 总样本数量

示例代码:

from sklearn.metrics import confusion_matrix
import pandas as pd


if __name__ == "__main__":

    # 样本集中共有6个恶性肿瘤样本, 4个良性肿瘤样本
    y_true = ["恶性", "恶性", "恶性", "恶性", "恶性","恶性",
              "良性", "良性", "良性", "良性"]

    labels = ["恶性", "良性"]
    dataframe_labels = ["恶性(正例)", "良性(反例)"]

    # 1. 模型 A: 预测对了3个恶性肿瘤样本, 4个良性肿瘤样本
    print("模型A:")
    print("-" * 13)
    y_pred = ["恶性", "恶性", "恶性", "良性", "良性", "良性",
              "良性", "良性", "良性", "良性"]
    result = confusion_matrix(y_true, y_pred, labels=labels)
    print(pd.DataFrame(result,
                       columns=dataframe_labels,
                       index=dataframe_labels))

    print()

    # 2. 模型 B: 预测对了6个恶性肿瘤样本, 1个良性肿瘤样本
    print("模型B:")
    print("-" * 13)
    y_pred = ["恶性", "恶性", "恶性", "恶性", "恶性", "恶性",
              "恶性", "恶性", "恶性", "良性"]

    result = confusion_matrix(y_true, y_pred, labels=labels)
    print(pd.DataFrame(result,
                       columns=dataframe_labels,
                       index=dataframe_labels))

输出结果:

模型A:
-------------
        恶性(正例)  良性(反例)
恶性(正例)       3       3
良性(反例)       0       4

模型B:
-------------
        恶性(正例)  良性(反例)
恶性(正例)       6       0
良性(反例)       3       1

2.2 精度(查准率)

精度也叫做查准率,指的是对正例样本的预测准确率。比如:我们把恶性肿瘤当做正例样本,则我们就需要知道模型对恶性肿瘤的预测准确率。

由于,我们预测结果中,有两种正例:原来就是正例被预测为正例,原来是假例被预测为正例,所以,我们想知道真正正例占预测结果中所有正例的比例,即:恶性肿瘤的查准率。
在这里插入图片描述
例子:
样本集中有 6 个恶性肿瘤样本,4 个良性肿瘤样本,我们假设恶性肿瘤为正例,则:

  1. 模型 A:预测对了 3 个恶性肿瘤样本,4 个良性肿瘤样本

    1. 真正例 TP 为:3
    2. 伪反例 FN 为:3
    3. 假正例 FP 为:0
    4. 真反例 TN:4
    5. 精度:3/(3+0) = 100%
  2. 模型 B:预测对了 6 个恶性肿瘤样本,1个良性肿瘤样本

    1. 真正例 TP 为:6
    2. 伪反例 FN 为:0
    3. 假正例 FP 为:3
    4. 真反例 TN:1
    5. 精度:6/(6+3) = 67%

示例代码:

from sklearn.metrics import precision_score


if __name__ == "__main__":

    # 样本集中共有6个恶性肿瘤样本, 4个良性肿瘤样本
    y_true = ["恶性", "恶性", "恶性", "恶性", "恶性","恶性",
              "良性", "良性", "良性", "良性"]

    # 1. 模型 A: 预测对了3个恶性肿瘤样本, 4个良性肿瘤样本
    y_pred = ["恶性", "恶性", "恶性", "良性", "良性", "良性",
              "良性", "良性", "良性", "良性"]
    result = precision_score(y_true, y_pred, pos_label="恶性")
    print("模型A精度:", result)


    # 2. 模型 B: 预测对了6个恶性肿瘤样本, 1个良性肿瘤样本
    y_pred = ["恶性", "恶性", "恶性", "恶性", "恶性", "恶性",
              "恶性", "恶性", "恶性", "良性"]

    result = precision_score(y_true, y_pred, pos_label="恶性")
    print("模型B精度:", result)

输出结果:

模型A精度: 1.0
模型B精度: 0.67

通过精度指标,可以评估模型对正例样本的预测准确率的能力。

2.3 召回率(查全率)

召回率也叫做查全率,指的是预测为真正例样本占所有真实正例样本的比重。例如:我们把恶性肿瘤当做正例样本,则我们想知道模型是否能把所有的恶性肿瘤患者都预测出来。
在这里插入图片描述
例子:
样本集中有 6 个恶性肿瘤样本,4 个良性肿瘤样本,我们假设恶性肿瘤为正例,则:

  1. 模型 A:预测对了 3 个恶性肿瘤样本,4 个良性肿瘤样本

    1. 真正例 TP 为:3
    2. 伪反例 FN 为:3
    3. 假正例 FP 为:0
    4. 真反例 TN:4
    5. 精度:3/(3+0) = 100%
    6. 召回率:3/(3+3)=50%
  2. 模型 B:预测对了 6 个恶性肿瘤样本,1个良性肿瘤样本

    1. 真正例 TP 为:6
    2. 伪反例 FN 为:0
    3. 假正例 FP 为:3
    4. 真反例 TN:1
    5. 精度:6/(6+3) = 67%
    6. 召回率:6/(6+0)= 100%

示例代码:

from sklearn.metrics import recall_score


if __name__ == "__main__":

    # 样本集中共有6个恶性肿瘤样本, 4个良性肿瘤样本
    y_true = ["恶性", "恶性", "恶性", "恶性", "恶性","恶性",
              "良性", "良性", "良性", "良性"]

    # 1. 模型 A: 预测对了3个恶性肿瘤样本, 4个良性肿瘤样本
    y_pred = ["恶性", "恶性", "恶性", "良性", "良性", "良性",
              "良性", "良性", "良性", "良性"]
    result = recall_score(y_true, y_pred, pos_label="恶性")
    print("模型A精度:", result)


    # 2. 模型 B: 预测对了6个恶性肿瘤样本, 1个良性肿瘤样本
    y_pred = ["恶性", "恶性", "恶性", "恶性", "恶性", "恶性",
              "恶性", "恶性", "恶性", "良性"]

    result = recall_score(y_true, y_pred, pos_label="恶性")
    print("模型B精度:", result)

输出结果:

模型A精度: 0.5
模型B精度: 1.0

通过召回率,我们可以评估模型对所有正样本是否能全部预测出来的能力。

2.4 F1-score

如果我们对模型的精度、召回率都有要求,希望知道模型在这两个评估方向的综合预测能力如何?则可以使用 F1-score 指标。

需要注意的是:

  1. 如果我们想要提高模型的精度,则需要减少样本的数量。
  2. 如果我们想要提高模型的召回率,则需要增加样本数量。

模型的精度、召回率是一对矛盾的存在。所以,模型在考量模型的精度、召回率的话,只能在两者之间取得一个平衡,即:精度差不多的情况,召回率也差不多。
在这里插入图片描述
此处,F1-使用的是精度、召回率的调和平均数。

  1. P 和 R 中的最小值会影响到 F1 score ,例如:如果一个指标接近于 0,另一个指标则接近于 1,则 F1-score 接近于 0。
  2. 两个都高则 F1-score 也高,比较重视较小值的重要性。

样本集中有 6 个恶性肿瘤样本,4 个良性肿瘤样本,我们假设恶性肿瘤为正例,则:

  1. 模型 A:预测对了 3 个恶性肿瘤样本,4 个良性肿瘤样本

    1. 真正例 TP 为:3
    2. 伪反例 FN 为:3
    3. 假正例 FP 为:0
    4. 真反例 TN:4
    5. 精度:3/(3+0) = 100%
    6. 召回率:3/(3+3)=50%
    7. F1-score:(2*3)/(2*3+3+0)=67%
  2. 模型 B:预测对了 6 个恶性肿瘤样本,1个良性肿瘤样本

    1. 真正例 TP 为:6
    2. 伪反例 FN 为:0
    3. 假正例 FP 为:3
    4. 真反例 TN:1
    5. 精度:6/(6+3) = 67%
    6. 召回率:6/(6+0)= 100%
    7. F1-score:(2*6)/(2*6+0+3)=80%

示例代码:

from sklearn.metrics import f1_score


if __name__ == "__main__":

    # 样本集中共有6个恶性肿瘤样本, 4个良性肿瘤样本
    y_true = ["恶性", "恶性", "恶性", "恶性", "恶性","恶性",
              "良性", "良性", "良性", "良性"]

    # 1. 模型 A: 预测对了3个恶性肿瘤样本, 4个良性肿瘤样本
    y_pred = ["恶性", "恶性", "恶性", "良性", "良性", "良性",
              "良性", "良性", "良性", "良性"]
    result = f1_score(y_true, y_pred, pos_label="恶性")
    print("模型Af1-score:", result)


    # 2. 模型 B: 预测对了6个恶性肿瘤样本, 1个良性肿瘤样本
    y_pred = ["恶性", "恶性", "恶性", "恶性", "恶性", "恶性",
              "恶性", "恶性", "恶性", "良性"]

    result = f1_score(y_true, y_pred, pos_label="恶性")
    print("模型Bf1-score:", result)

输出结果:

模型A精度: 0.67
模型B精度: 0.8

综合来考量精度、召回率,模型 B 优于 模型 A。

2.5 AUC(模型排序能力)

2.5.1 AUC 理解

在前面,我们提到了正样本和负样本,如何去划分正负样本呢?

设定一个阈值,比如某个样本归为 1 类的概率超过 50%,则将其视为正样本,反之则将其视为负样本,这个阈值也可以调整为 30%、40%、80% 等等。此时,阈值的调整最终会影响到正样本、负样本的数量,进而影响到查全率、查准率、F1-score 等分类评估指标。

例如:班里同学都已经考试完了,拿到了考试分数。此时,如果及格分数调整为 20,则就会有 80 个人及格(正样本),如果及格分数线调整为 80,则就会有 20 个人及格(正样本)。

也就是说,查全率、查准率、F1-score 这些评估指标的结果是受到阈值的影响。

**AUC 指标则是不直接考虑阈值的一种评估模型分类性能的指标,**其主要考虑的是模型对正例样本、负例样本的辨别能力,主要是通过对正负样本预测为正例的概率进行排序来识别的:

比如:我们使用逻辑回归输出对 7 个样本(3正4负)进行分类为正例的预测概率:

**说明:**正(90%) 表示:原来是正样本,被预测为正样本的概率为:90%

模型A:正(90%) 正(80%) 负(78%) 正(51%) 负(48%) 负(40%) 负(23%)

模型B:正(90%) 正(80%) 正(78%) 负(49%) 负(48%) 负(40%) 负(23%)

从排序结果来看,模型 B 能够将正例的样本预测为正例概率都很高,负类样本预测为正例的概率都很低,说明模型对正、负样本的辨别能力很强。

我们也可以说,任意从样本集中选择一对正负样本,如果正样本的预测概率高于负样本的预测概率,则说明该模型的对正负样本的辨别能力很强。

也可以说,真正正例的样本越靠近左侧,则说明,模型预测能力就越强。

示例代码:

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score


if __name__ == "__main__":

    names = ['Sample code number',
             'Clump Thickness',
             'Uniformity of Cell Size',
             'Uniformity of Cell Shape',
             'Marginal Adhesion',
             'Single Epithelial Cell Size',
             'Bare Nuclei',
             'Bland Chromatin',
             'Normal Nucleoli',
             'Mitoses',
             'Class']
    # 读取数据
    data = pd.read_csv("./data/breast-cancer-wisconsin.data", names=names)

    # 缺失值处理
    data = data.replace(to_replace="?", value=np.nan)
    data = data.dropna()

    # 确定特征值、目标值
    x = data.iloc[:, 1:-1]
    y = data["Class"]

    # 分割数据集
    x_train, x_test, y_train, y_test = \
        train_test_split(x, y, random_state=5, test_size=0.2)

    # 标准化
    transfer = StandardScaler()
    x_train = transfer.fit_transform(x_train)
    x_test = transfer.fit_transform(x_test)

    # 模型训练
    estimator = LogisticRegression()
    estimator.fit(x_train, y_train)

    # 预测评估
    y_test_pred_proba = estimator.predict_proba(x_test)
    # 参数1:测试样本的真实目标值
    # 参数2:测试样本的预测概率值,取第二列值
    auc = roc_auc_score(y_test, y_test_pred_proba[:, 1])
    print("auc:", auc)

2.6 ROC曲线绘制

2.6.1 ROC曲线理解

ROC 曲线:我们分别考虑正负样本的情况:

  1. 正样本中被预测为正样本的概率,即:TPR (True Positive Rate)
  2. 负样本中被预测为正样本的概率,即:FPR (False Positive Rate)

我们希望 TPR 尽可能的大,FPR 尽可能小。这样的话,就可以将正样本排序到左侧,负样本排序到右侧。我们接下来,在考虑不同阈值情况下,TPR 和 FPR 的变化情况,构成了 ROC 曲线。如下图所示:
在这里插入图片描述
假设:恶性肿瘤为正例

横轴:负样本中预测为正样本的概率,比如:良性肿瘤中预测为恶性肿瘤的概率

纵轴:正样本中预测为正样本的概率,比如:恶性肿瘤中预测为恶性肿瘤的概率

  1. ROC 曲线图像中,4 个特殊点的含义:
    1. (0, 0) 表示所有的正样本都预测为错误,所有的负样本都预测正确
    2. (1, 0) 表示所有的正样本都预测错误,所有的负样本都预测错误
    3. (1, 1) 表示所有的正样本都预测正确,所有的负样本都预测错误
    4. (0, 1) 表示所有的正样本都预测正确,所有的负样本都预测正确
  2. 我们发现:
    1. 我们发现:图像越靠近 (0,1) 点则模型对正负样本的辨别能力就越强
    2. 我们发现:图像越靠近 (0, 1) 点则 ROC 曲线下面的面积就会越大
    3. AUC 是 ROC 曲线下面的面积,该值越大,则模型的辨别能力就越强
    4. AUC 范围在 [0, 1] 之间
    5. 当 AUC= 1 时,该模型被认为是完美的分类器,但是几乎不存在完美分类器
    6. 当 AUC <= 0.5 时,模型区分正负样本的就会变得模棱两可,近似于随机猜测

2.6.2 ROC曲线绘制

假设:在网页某个位置有一个广告图片或者文字,该广告共被展示了 6 次,有 2 次被浏览者点击了。每次点击的概率如下:

样本是否被点击预测点击概率
110.9
200.7
310.8
400.6
500.5
600.4

根据预测点击概率排序之后:

样本是否被点击预测点击概率
110.9
310.8
200.7
400.6
500.5
600.4

绘制 ROC 曲线:

  1. 阈值:0.9
    1. 原本为正例的 1、3 号的样本中 3 号样本被分类错误,则 TPR = 1/2 = 0.5
    2. 原本为负例的 2、4、5、6 号样本没有一个被分为正例,则 FPR = 0
  2. 阈值:0.8
    1. 原本为正例的 1、3 号样本被分类正确,则 TPR = 2/2 = 1
    2. 原本为负例的 2、4、5、6 号样本没有一个被分为正例,则 FPR = 0
  3. 阈值:0.7
    1. 原本为正例的 1、3 号样本被分类正确,则 TPR = 2/2 = 1
    2. 原本为负类的 2、4、5、6 号样本中 2 号样本被分类错误,则 FPR = 1/4 = 0.25
  4. 阈值:0.6
    1. 原本为正例的 1、3 号样本被分类正确,则 TPR = 2/2 = 1
    2. 原本为负类的 2、4、5、6 号样本中 2、4 号样本被分类错误,则 FPR = 2/4 = 0.5
  5. 阈值:0.5
    1. 原本为正例的 1、3 号样本被分类正确,则 TPR = 2/2 = 1
    2. 原本为负类的 2、4、5、6 号样本中 2、4、5 号样本被分类错误,则 FPR = 3/4 = 0.75
  6. 阈值 0.4
    1. 原本为正例的 1、3 号样本被分类正确,则 TPR = 2/2 = 1
    2. 原本为负类的 2、4、5、6 号样本全部被分类错误,则 FPR = 4/4 = 1

(0, 0.5)、(0, 1)、(0.25, 1)、(0.5, 1)、(0.75, 1)、(1, 1)

由 TPR 和 FPR 构成的 ROC 图像为:
在这里插入图片描述

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值