一、常用的模型评估方法
1.1 准确率
准确率是模型预测正确数量占总量的比例。
准确率(Accuracy)是一个非常直观的性能评价指标,它表示的是分类正确的样本数占总样本数的比例。在二分类问题中,准确率可以通过混淆矩阵中的真阳性(True Positive, TP)、真阴性(True Negative, TN)、假阳性(False Positive, FP)和假阴性(False Negative, FN)来计算。
准确率的计算公式为:
准确率 = 预测正确的样本数 / 总样本数
也就是 准确率 = (真正例 + 真反例) / (真正例 + 真反例 + 假正例 + 假反例)
Accuracy = (TP + TN) / (TP + TN + FP + FN )
其中,TP 是被正确预测为正类的样本数,TN 是被正确预测为负类的样本数,FP 是被错误预测为正类的样本数,而 ( FN ) 是被错误预测为负类的样本数。
例如,池塘里总共有2000只动物,包括1400条鲤鱼、300只虾和300只鳖。进行一次捕捞操作后,捕获了700条鲤鱼(真正例,TP),但也捕获了200只虾和100只鳖(假正例,FP)。同时,还有700条鲤鱼未被捕获(假反例,FN),而所有的虾和鳖都未被捕获(真反例,TN)。根据这些信息,可以计算出:准确率(Accuracy)是所有预测正确的样本数除以总样本数。
在这个例子中,准确率是(700+TN)/(700+200+100+TN),由于TN是所有未被捕获的虾和鳖的数量,即600,所以准确率是(700+600)/2000 = 1300 / 2000 = 65%。
1.2 精确率
精确率是预测为正类中实际为正类的比例。
精确率(Precision)是分类模型评估中的一个核心指标,它衡量的是预测结果中正类的正确性。具体来说,精确率的计算公式为:
精确率 = 真正例 / (真正例 + 假正例)
Precision=TP / (TP+FP)
其中,TP(True Positives)表示真正例的数量,即正确预测为正类的样本数;而FP(False Positives)表示假正例的数量,即错误预测为正类的样本数。这个公式的含义是在所有被预测为正类的样本中,实际上有多少比例是真正的正类。
以一个简单的例子来说明,假设有一个池塘里有1400条鲤鱼、300只虾和300只鳖。如果使用一种方法来捕捞鲤鱼,捕获了700条鲤鱼,但也同时捕获了200只虾和100只鳖。在这个情况下,如果我们将鲤鱼视为正类,那么真正例(TP)是700,假正例(FP)是捕获的非鲤鱼数量,即200只虾和100只鳖的总和,共300。因此,精确率就是700(TP)除以1000(TP+FP),即70%。
1.3 召回率
召回率是实际为正的样本中被预测为正样本的概率。
召回率(Recall)是分类问题中一个重要的评估指标,它衡量的是模型对正类样本识别的能力。换句话说,召回率告诉我们在所有真实值为正的样本中,有多少比例被模型正确地预测为正。其计算公式为:
召回率 = 真正例 / (真正例 + 假反例)
Recall=TP/ (TP+FN)
其中, TP )(True Positives)表示真正例的数量,即正确预测为正类的样本数;FN (False Negatives)表示假反例的数量,即错误预测为负类的样本数。这个公式的含义是在所有实际上是正类的样本中,有多少是被模型正确识别的。
以一个简单的例子来说明,假设有一个池塘里有1400条鲤鱼、300只虾和300只鳖。如果使用一种捕捞方法,捕获了700条鲤鱼,但同时也有700条鲤鱼没有被捕获。在这个情况下,如果我们将鲤鱼视为正类,那么真正例(TP)是700,假反例(FN)是未被捕获的700条鲤鱼。因此,召回率就是700(TP)除以1400(TP+FN),即0.5,或者说是50%。
1.4 ROC曲线
ROC曲线,也称为受试者工作特征曲线(Receiver Operating Characteristic Curve),是一种用于评估分类模型性能的图形化工具。
ROC曲线通过在不同阈值下绘制真阳性率(True Positive Rate,TPR)和假阳性率(False Positive Rate,FPR)之间的关系来展示分类器的性能。TPR也就是敏感度或召回率,表示的是所有实际为正类的样本中被正确预测为正类的样本比例;FPR则是被错误预测为正类的负类样本占所有实际为负类的样本的比例。
在ROC曲线中,横坐标是FPR:假正率(False Positive Rate,FPR)
纵坐标是TPR:真正率(True Positive Rate,TPR)
曲线越接近左上角,即FPR趋近于0而TPR趋近于1,分类器的性能越好。ROC曲线下的面积被称为AUC(Area Under the Curve),AUC值越接近1,表示分类器的整体性能越好;反之,AUC值越接近0.5(即接近随机猜测的水平),性能越差。
ROC曲线的主要用途有两个:一是评价某个或多个指标对两类被试(如病人和健康人)分类/诊断的效果;二是寻找最佳的指标临界值使得分类效果最好。
此外,不同的算法模型对应不同的ROC曲线,超参数不同的模型也对应不同的ROC曲线。一个理想的模型应该有一个ROC曲线位于随机猜测线(通常是45度对角线)上方的区域,这意味着该模型具有良好的分类能力。
1.5 PR曲线
PR曲线,也称为精确率-召回率曲线(Precision-Recall Curve),是一个用于评估分类模型性能的图表,特别适用于数据不平衡的情况。
PR曲线是通过在不同的分类阈值上计算精确率(Precision)和召回率(Recall)来绘制的。具体来说:
- 横坐标是召回率(Recall):它表示的是所有实际为正类的样本中,被正确预测为正类的样本比例。
- 纵坐标是精确率(Precision):它表示的是所有被预测为正类的样本中,实际为正类的样本比例。
PR曲线通常从坐标原点(0,0)开始,随着分类阈值的变化,曲线会向右上方延伸。理想情况下,一个优秀的分类模型应该能在保持高召回率的同时,也能保持较高的精确率,这反映在PR曲线上就是接近于1*1的正方形的一条曲线。
在实际应用中,可以通过调整分类模型的阈值来获得不同的点,从而绘制出PR曲线。通过观察PR曲线的形状,我们可以对模型在不同情境下的表现有一个直观的了解。例如,如果一个模型在所有正例都被正确分类之前没有将任何负例误判为正例,那么PR曲线将从原点垂直上升到(0,1)点,然后水平向右延伸至(1,1)点。这样的模型表现是非常理想的。然而,大多数实际情况下,模型的表现可能不会这样完美,因此PR曲线会在两点之间形成一条曲线。
二、ROC曲线和PR曲线的区别
ROC曲线和PR曲线都是用于评估分类模型性能的工具,它们在某些方面有相似之处,但在先验概率和适用情况上存在差异。
2.1 相同点
- 两者都是通过在不同的分类阈值下绘制曲线来展示模型的性能表现。
- 都可以用来比较不同模型之间的性能优劣,通过曲线下面积(AUC)来量化评估模型的分类性能。
2.2 不同点
- 先验概率:ROC曲线假设正负样本的先验概率相等,而PR曲线则假设正样本的先验概率远小于负样本的先验概率。因此,ROC曲线通常用于处理类别均衡的数据集,而PR曲线则更适合处理类别不平衡的数据集。
- 适用情况:ROC曲线主要用于二分类问题中的模型比较,表现为真正例率(TPR)和假正例率(FPR)的权衡。而PR曲线在有偏的数据集上,可以作为ROC曲线的一个替代选择。在视觉表现上,一个好的模型在ROC图上的表现一定是偏左上角的,而在PR曲线中一定是偏右上角的。
三、ROC曲线的绘制示例
不同k值下KNN算法对于电影分类的ROC曲线图
我们通过下列代码进行ROC曲线的绘制
这段代码的功能是使用KNN算法对电影类型进行分类,并绘制不同k值下的ROC曲线。首先,它导入了所需的库和模块,然后定义了一个数据集函数,该函数返回一个包含电影特征(如打斗次数或亲吻次数)的数组以及对应的电影类型标签(动作片或爱情片)。
然后,代码将数据集划分为训练集和测试集,并对标签进行二值化处理。接下来,它设置了k值的范围为1到3,并使用OneVsRestClassifier和KNeighborsClassifier创建一个分类器对象。
最后,代码绘制了不同k值下的ROC曲线,其中横坐标为假阳性率(False Positive Rate),纵坐标为真阳性率(True Positive Rate)。通过观察ROC曲线,可以评估分类器在不同k值下的性能。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import roc_curve, auc
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import label_binarize
from sklearn.multiclass import OneVsRestClassifier
import numpy as np
import numpy as np
def Dataset():
data = np.array([[3, 100], [1, 90], [2, 81], [101, 10], [99, 5], [98, 2]])
labels = ['动作片', '动作片', '动作片', '爱情片', '爱情片', '爱情片']
return data, labels
data, labels = Dataset()
X_train, X_test, y_train, y_test = train_test_split(data, labels, test_size=0.5, random_state=42)
y_train = label_binarize(y_train, classes=['动作片', '爱情片'])
y_test = label_binarize(y_test, classes=['动作片', '爱情片'])
n_classes = y_train.shape[1]
k_range = k_range = range(1, 4)
classifier = OneVsRestClassifier(KNeighborsClassifier())
plt.figure()
plt.plot([0, 1], [0, 1], 'k--')
for k in k_range:
classifier.set_params(estimator__n_neighbors=k)
classifier.fit(X_train, y_train)
y_score = classifier.predict_proba(X_test)
y_test_reshaped = y_test.ravel() # 将y_test转换为一维数组并调整形状
fpr, tpr, _ = roc_curve(y_test_reshaped, y_score[:, 1].ravel()) # 使用一维数组计算ROC曲线
roc_auc = auc(fpr, tpr)
plt.plot(fpr, tpr, label='k = %d (area = %0.2f)' % (k, roc_auc))
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC curve for different k values')
plt.legend(loc="lower right")
plt.show()
3.1 简单数据集的ROC曲线图
def Dataset():
data = np.array([[3, 100], [1, 90], [2, 81], [101, 10], [99, 5], [98, 2]])
labels = ['动作片', '动作片', '动作片', '爱情片', '爱情片', '爱情片']
return data, labels
图3.1
3.2 图3.1ROC曲线图分析
图3.1 这个ROC曲线图有着以下问题
1.ROC曲线呈现出一个完美的直角三角形
因为数据集非常简单,而且特征空间的分布允许KNN模型在特定的k值下完美地分类测试数据。
以下是可能导致这种情况的几个原因:
-
数据集非常简单:这个数据集非常小,只有6个样本点,而且每个类别(动作片和爱情片)的样本在特征空间中是线性可分的。这意味着可以通过一条直线(或者在这种情况下,一个超平面)来完美地分隔两个类别。
-
KNN模型的特性:KNN模型是一种基于实例的学习,它根据最接近的k个邻居的类别来预测新样本的类别。在这个例子中,当k=3时,对于每个测试样本,它的三个最近邻居都来自同一个类别,这使得分类决策非常清晰。
-
OneVsRest策略:在这个例子中,使用了OneVsRestClassifier,它将多类问题分解为一系列的一对多(one-vs-all)问题。对于这个特定的数据集,这意味着KNN只需要在两个类别之间做出决策。如果KNN能够为每个类别完美地分类测试样本,那么ROC曲线就会显示出完美的性能。
2.为什么ROC曲线图在不同k值下是一样的
因为OneVsRestClassifier将问题转化为了多个二分类问题,每个类别都与其余类别进行比较。在这段代码中,只有两个类别(动作片和爱情片),所以实际上只有一个二分类问题。因此,无论k值如何变化,ROC曲线的形状都是一样的。
于是我们尝试增添数据集
3.3 增加数据集之后的ROC曲线图
增加20个数据集
def Dataset():
data = np.array([[3, 100], [1, 90], [2, 81], [101, 10], [99, 5], [98, 2]])
labels = ['动作片', '动作片', '动作片', '爱情片', '爱情片', '爱情片']
# 增加20个固定数据集
fixed_data = np.array([
[4, 110], [5, 120], [6, 130], [7, 140], [8, 150],
[9, 160], [10, 170], [11, 180], [12, 190], [13, 200],
[14, 210], [15, 220], [16, 230], [17, 240], [18, 250],
[19, 260], [20, 270], [21, 280], [22, 290], [23, 300]
])
fixed_labels = ['动作片', '动作片', '动作片', '动作片', '动作片',
'爱情片', '爱情片', '爱情片', '爱情片', '爱情片',
'动作片', '动作片', '动作片', '动作片', '动作片',
'爱情片', '爱情片', '爱情片', '爱情片', '爱情片']
data = np.concatenate((data, fixed_data), axis=0)
labels.extend(fixed_labels)
return data, labels
我们继续来看看它不同K值下的ROC曲线图
图3.2
3.4 图3.2ROC曲线图分析
不同k值下的ROC曲线可以通过计算曲线下的面积(AUC)来进行统计比较。AUC值越接近1,表示分类器的性能越好。因此,可以看出,当K值等于2时,AUC的值等于1.00,也就是说这条曲线的评估性能完美;当K值等于3时,AUC的值等于0.95,评估性能会比K值等于2时差一些;当K值等于1时,AUC的值等于0.85,所以K等于1时这条ROC曲线的评估性能是最差的。
3.5 不同K值下对ROC曲线图的影响
根据 图3.2 我们可以看出,k值在KNN算法中影响了模型的决策边界。以下是一些导致不同k值下ROC曲线图不一样的因素:
- 模型的泛化能力:较小的k值可能导致模型过拟合,因为它更多地依赖于局部的数据点;而较大的k值可能使模型过于简化,因为它考虑了更多的邻居来做出决策。
- 数据的特性:如果数据集中存在噪声或者类别之间的边界不明显,k值的选择将更加关键,因为它会影响模型对这些复杂情况的处理能力。
- 平衡性分析:ROC曲线可以帮助理解分类器在灵敏度(真正率)和特异性(假正率)之间的平衡。不同k值下,这种平衡可能会发生变化,从而导致ROC曲线图的差异。
- 统计比较:不同k值下的ROC曲线可以通过计算曲线下的面积(AUC)来进行统计比较。AUC值越接近1,表示分类器的性能越好。因此,不同k值可能会导致不同的AUC值,从而影响ROC曲线的形状。
- 混淆矩阵:ROC曲线是基于混淆矩阵中的真正率和假正率绘制的。不同k值可能会导致混淆矩阵中的元素发生变化,从而影响ROC曲线的形状。
- 样本数量:当使用不同的k值时,参与决策的近邻数量会有所不同,这可能会影响模型对样本数量的敏感度,尤其是在数据集较小的情况下。
- 随机性:在数据集较小或数据分布不均匀时,k值的选择可能会引入额外的随机性,导致ROC曲线的不稳定。
四、总结
根据这个实验,我们可以总结出:
1.当我们的数据集太过于简单时,ROC曲线就可能非常完美,并且不同K值下的 ROC曲线图都可能一样,就如我们的 图3.1 。因此,我们在进行实验时的数据集应该是多样化的,多数量的。
2.当我们的数据集足够大时,不同K值下的ROC曲线图可能都会不一样,正如图 3.2 ,我们的K值变化也会影响着ROC曲线图的评估性能,并且不是K值越大(或越小)ROC曲线图的性能越好,因此,我们在进行KNN邻近算法时,应该选取合适的K值进行KNN分类。