目录
1.常见的分类模型评估指标
1.1混淆矩阵
混淆矩阵(Confusion Matrix)是在机器学习中,用于对分类模型的性能进行评估的一种方法。混淆矩阵展示了模型在分类任务中的预测结果与实际标签之间的对应关系。它由四个因素组成:真正例(TP)、假正例(FP)、真负例(TN)、假负例(FN)。表格关系如下所示
通过混淆矩阵,我们可以通过多种性能指标来评估分类模型的性能,例如准确率、精准率、召回率等,下面为常见的精确率和召回率的计算公式。
精确率计算公式如下:
精准率其实就是算出真正例在所有正例(真正例加假正例)当中的占比。
通俗一点来说(拿西瓜举例),就是所有的西瓜中有多少好瓜。
召回率计算公式如下:
召回率就是真正例在所预测样本当中的占比。
通俗一点来说,就是好瓜当中有多少预测正确。
1.2AUC-ROC曲线
首先AUC-ROC曲线是在不同阈值设置的条件下,分类问题的性能度量。ROC是概率曲线,AUC的含义为正负类可正确分类的程度。AUC越高,模型性能越好。ROC的面积也就是AUC曲线(其实就是与坐标轴围成的面积),因此ROC曲线越陡越好。
可以参照以下AUC的一般判断标准
0.5 - 0.7: 效果较低,但用于预测股票已经很不错了
0.7 - 0.85: 效果一般
0.85 - 0.95: 效果很好
0.95 - 1: 效果非常好,但一般不太可能
1.3PR曲线
PR曲线:P为precision即精准率(查准率),R为recall即召回率,所以P-R曲线是反映了准确率与召回率之间的关系。一般横坐标为recall,纵坐标为precision。PR曲线常被用在信息提取领域,同时当我们的数据集中类别分布不均衡时我们可以用PR曲线代替。是数据挖掘中常见的评价指标。
PR曲线的主要指标有两个:查全率和查准率
查全率的公式如下
查准率的公式如下
PR曲线如下图所示
PR曲线也是跟ROC曲线相似,曲线越靠近右上方性能越好(例如上图的灰色曲线性能优于蓝色曲线)。换句话说,与坐标轴围成的面积越大,性能越好。亦或者,也可以通过平衡点F判断。平衡点F也就是查全率等于查准率的点。F的计算公式如下,F值越大,性能越好。
2.AUC-ROC曲线
2.1绘制AUC-ROC曲线
准备工作:首先我们要导入roc_curve的库,并且我们需要准备自己的数据集(y_test,y_pred)。以下是可能需要运用到的库。
import os
import cv2
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from PIL import Image
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve
from sklearn.metrics import accuracy_score, precision_recall_curve, auc
其次,我们需要利用roc_curve函数算出fpr、tpr、thresholds(假正率、真正率、阈值)。然后利用plot函数绘制ROC曲线。
# 计算TPR和FPR
fpr, tpr, thresholds = roc_curve(y_test, y_pred)
# 绘制ROC曲线
plt.plot(fpr, tpr, label='ROC curve')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend()
plt.show()
2.2AUC-ROC曲线分析
由于博主是基于自己上次所做的KNN分类绘制的AUC-ROC曲线,因为该数据集在KNN分类器下的准确率为0.53(此时的k值为5),因此绘制出的AUC-ROC曲线较为平滑。以下为绘制的AUC-ROC曲线图。
我们可以通过改变不同的K值,从而观察ROC曲线的变化。
当k值等于3的时候,此时的模型准确率为0.51,该ROC曲线如下图所示。
分析:我们可以观察到曲线更加趋于平滑了,当k值变大的时候,我们的模型准确率下降。因此ROC曲线所围成的面积也随之变小,模型性能也下降了。
为什么会出现曲线过于平滑的原因呢?
分析:因为博主采用的是猫狗图片数据集,加上KNN模型的泛化性较差。因此在进行对图片分类的任务的时候,模型的准确率较差。在对该数据集进行分类的时候,knn模型的准确率也仅有0.53,所以导致在测试集进行测试的时候,会出现一部分的识别错误,在ROC曲线上就会体现出曲线过于平滑的情况。
如何计算它的tpr、fpr、threshold呢,我们举一个具体的例子来说明。
y_true=np.array([0, 0, 0, 1, 1, 0, 0, 0, 1, 0])
y_score=np.array([0, 0, 0, 1, 1, 0, 0, 0, 0, 0])
fpr,tpr,threshold=roc_curve(y_true,y_score)
y_true为真实结果数据,y_score为标签数据,threshold为阈值。
threshold返回的结果是y_score内的元素去重后加入一个‘最大值+1’的值降序排序后组成的数据。
由此我们可以知道threshold输出结果为[2,1,0]。
当index = 0时,threshold[0] = 2,假设y_score大于等于2的元素对应index在y_true中的样本为正样本,其他为负样本,然后与y_true对应元素对比组成混淆矩阵,因没有大于等于2的值,因此TP和FP都为0。即tpr[0]=0/3 = 0,fpr[0] = 0/7 = 0。
同理,可以得到index = 1时,threshold[1] = 1。TP = 2,FP = 0,即tpr[1]=2/3=0.67,fpr[1]=0/7=0。
最终的结果为:tpr=array([0. , 0.5, 0.5, 1. , 1.]),fpr=array([0. , 0. , 0.5, 0.5, 1. ])。
3.PR曲线
3.1绘制PR曲线
首先导入我们可能所需要用到的库,如下所示。
import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics import precision_recall_curve
PR曲线我们则需要计算出它的查全率和查准率,我们可以调用precision_recall_curve函数来实现。并且我们可以通过auc函数来计算出PR曲线下的面积。
# 计算PR曲线
precision, recall, _ = precision_recall_curve(y_test, y_pred)
pr_auc = auc(recall, precision)
print("PR曲线下的面积:", pr_auc)
# 绘制PR曲线
plt.plot(recall, precision, label='PR curve (area = %0.2f)' % pr_auc)
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.legend()
plt.show()
3.2PR曲线分析
基于博主自己数据集绘制的PR曲线如下图所示。
从图中可以看出,博主所选择的数据集利用knn训练的模型性能一般。大家可根据自己的数据集进行选择,又或者可以直接调用支持向量机的分类器等。
通过观察PR曲线,我们可以分析分类模型在不同阈值下的性能。PR曲线越靠近左上角,表示模型的性能越好,即在召回率较高的情况下,精确率也较高。相反,PR曲线越靠近对角线,表示模型的性能较差,即在召回率较高的情况下,精确率较低。
4.总结
AUC-ROC曲线和PR曲线的差异:
- 关注指标不同:ROC曲线使用假阳性率(FPR)作为横坐标,而PR曲线则使用召回率(Recall)作为横坐标。这意味着ROC曲线关注的是模型对负例的识别能力,而PR曲线关注的是模型对正例的识别能力。
- 适用情况不同:在类别不平衡问题中,由于主要关心的是正例,PR曲线被广泛认为优于ROC曲线。这是因为PR曲线的两个指标都聚焦于正例,而ROC曲线同时考虑了正例和负例。
因此,大家可以按照自己的需求所选择对应的曲线评估模型性能。
以下为博主实现模型分类的源码(数据集下载地址在前面博文可找到)。
import os
import cv2
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from PIL import Image
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve
from sklearn.metrics import accuracy_score, precision_recall_curve, auc
#0代表猫,1代表狗
def image_to_feature_matrix(image_path, size=(64, 64)):
# 读取图片文件
img = cv2.imread('C:\\AI\\Lib\\cats_dogs_dataset\\'+image_path)
# 缩放图片
img = cv2.resize(img, size)
# 将图片转换为灰度图
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 将灰度图转换为特征向量
feature_vector = gray_img.flatten()
return feature_vector
def file2matrix(filename):
fr = open(filename)
arrayOLines = fr.readlines()
numberOfLines = len(arrayOLines)
classLabelVector = []#用于存放标签
img = []#用于存放图片
index = 0
for line in arrayOLines:
line = line.strip()
listFromLine = line.split('\t')#将数据集每一行都分割来 分割后为'cats/cat.4987.jpg 0'
for item in listFromLine:
img_path, classLabel = item.split(' ')
img_data = image_to_feature_matrix(img_path)
img.append(img_data)
classLabelVector.append(int(classLabel))
index += 1
return classLabelVector, img
def classify(inX, X_train, labels, k):#knn算法
dataSetSize = len(X_train)
diffMat = np.tile(inX, (dataSetSize, 1)) - X_train
sqDiffMat = diffMat**2
sqDistance = sqDiffMat.sum(axis=1)
distances = sqDistance**0.5
sortedDisIndicies = distances.argsort()
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDisIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
sortedClassCount = sorted(classCount.items(), key=lambda x: x[1], reverse=True)
return sortedClassCount[0][0]
#绘制ROC曲线
if __name__ == "__main__":
filename = 'C:\\AI\\Lib\\cats_dogs_dataset\\test.txt'
classLabelVector, img = file2matrix(filename)
print(img)
print(classLabelVector)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(img, classLabelVector, test_size=0.2, random_state=42)
# 创建KNN分类器
knn = KNeighborsClassifier(n_neighbors=10)
#通过输入预测
img_path = 'cats/cat.4358.jpg'
inX = image_to_feature_matrix(img_path)
knn1 = classify(inX, X_train, y_train, k=3)
print(knn1)
# 训练模型
knn.fit(X_train, y_train)
# 预测
y_pred = knn.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print("准确率:", accuracy)
#散点图分布
plt.scatter(range(len(y_pred)), y_pred, c='r', label='dog')
plt.scatter(range(len(y_test)), y_test, c='b', label='cat')
plt.xlabel('Index')
plt.ylabel('Class')
plt.legend()
plt.show()
# 计算TPR和FPR
fpr, tpr, thresholds = roc_curve(y_test, y_pred)
# 绘制ROC曲线
plt.plot(fpr, tpr, label='ROC curve')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend()
plt.show()
# 计算PR曲线
precision, recall, _ = precision_recall_curve(y_test, y_pred)
pr_auc = auc(recall, precision)
print("PR曲线下的面积:", pr_auc)
# 绘制PR曲线
plt.plot(recall, precision, label='PR curve (area = %0.2f)' % pr_auc)
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.legend()
plt.show()