一、引言
分类模型评估是指在构建并训练完成一个分类模型后,通过一系列定量和定性方法来衡量其性能、准确度以及泛化能力的过程。分类模型旨在将数据实例分配到预定义的一组类别中,评估分类模型的核心目标是确定模型在新数据上的表现如何,即模型是否能够有效地依据输入特征正确地预测未知样本所属的类别。
二、分类模型评估常用方法
1. 混淆矩阵 (Confusion Matrix)
定义:混淆矩阵是一个表格,列出了模型在预测时各类别间的实际与预测分布。
对于二分类问题,矩阵包含四个基本项:
真正例 (True Positives, TP),假正例 (False Positives, FP),真反例 (True Negatives, TN),假反例 (False Negatives, FN)。对于多分类问题,矩阵扩展为每个类别的两两对比。
作用:减少单次划分数据带来的偶然性,提供更稳健的模型评估,可用于模型选择和超参数调整。
2. 准确率 (Accuracy)
定义:准确率是正确分类样本数占总样本数的比例,计算公式为:
( Accuracy = \frac{TP + TN}{TP + TN + FP + FN} )
作用:简洁明了地表示模型的整体正确分类能力,但对类别不平衡问题敏感。
3. 精确率 (Precision)
定义:对于某一类别,精确率是该类别被正确预测为正例的样本数占所有被预测为该类别的样本数的比例,计算公式为:
( Precision = \frac{TP}{TP + FP} )
作用:衡量模型对某类别的预测结果中,真正属于该类别的比例,有助于理解模型在避免假阳性方面的表现。
4. 召回率 (Recall)
定义:召回率同样针对某一类别,表示该类别实际正例中被正确识别的比例,计算公式为:
( Recall = \frac{TP}{TP + FN} )
作用:评估模型识别全部正例的能力,特别是在关注减少漏检(假阴性)的应用场景中,召回率尤为重要。
5. F1 Score
定义:F1 Score是精确率和召回率的调和平均数,兼顾两者的表现,计算公式为:
( F1 = 2 \times \frac{Precision \times Recall}{Precision + Recall} )
作用:提供单一数值来综合衡量模型在精确率和召回率上的平衡表现,尤其适用于需要同时考虑这两方面性能的场景。
6. AUC-ROC曲线
描绘模型在不同阈值下的真正例率(TPR)与假正例率(FPR)的关系,曲线下面积(AUC)值越接近1,模型区分正负类的能力越强。
三、ROC曲线的绘制(KNN为例)
1.数据准备与模型训练:
加载数据:加载包含特征(X)和标签(y)的数据集。
数据预处理:如有必要,对数据进行清洗、标准化、编码等预处理操作。
划分数据集:使用train_test_split函数将数据集划分为训练集和测试集。
训练模型:以svm为例,选择适当的分类器(如SVC),用训练集数据训练模型。
2.计算ROC曲线所需数据:
预测概率:使用训练好的模型对测试集数据进行预测,获取每个样本属于正类的概率。
3.绘制ROC曲线:
使用roc_curve函数计算ROC曲线的关键点:输入真实标签(y_test)和预测概率(y_scores),得到假正例率(FPR)、真正例率(TPR)和阈值数组。
4.代码展示:
import numpy as np
import operator
import matplotlib.pyplot as plt
# 训练数据
def DataSet():
group = np.array([[3, 104], [2, 100], [1, 81], [10, 80], [10, 51], [51, 10], [76, 21], [101, 10], [99, 5], [98, 2]])
lables = ['red', 'red', 'red', 'red', 'red', 'green', 'green', 'green', 'green', 'green']
return group, lables
# 测试数据
def TestData():
test_x = np.array(
[[68, 36], [23, 58], [8, 96], [69, 27], [25, 59], [32, 16], [94, 45], [35, 21], [51, 6], [88, 39], [92, 51],
[31, 78], [34, 98], [10, 27], [89, 1], [48, 5], [4, 43], [11, 68], [12, 36], [3, 75], [54, 25], [96, 74],
[41, 34], [91, 32], [79, 41], [30, 81], [50, 6], [86, 49], [58, 33], [89, 30], [85, 58], [77, 51], [35, 75],
[4, 66], [85, 69], [54, 9], [53, 50], [5, 70], [42, 97], [46, 17], [52, 75], [59, 52], [93, 72], [67, 56],
[56, 57], [88, 84], [82, 87], [63, 74], [0, 31], [83, 50]])
return test_x
def KNN(test_x, x_lables, y_lables, k):
result1 = []
for i in range(test_x.shape[0]):
# 计算两个颜色之间的欧氏距离
x_lables_size = x_lables.shape[0] # 取得矩阵的行数
distances = (np.tile(test_x[i], (x_lables_size, 1)) - x_lables) ** 2 # tilt函数是把(矩阵,(行,列))向复制k次
ad_distance = distances.sum(axis=1)
sq_distance = ad_distance ** 0.5 # 开方后得到最后的欧式距离
ed_distance = sq_distance.argsort() # 得到距离排序后的索引
# 统计距离最近的k个点
classdict = {}
for i in range(k):
voteI_lable = y_lables[ed_distance[i]] # 从最近的开始取第i个
classdict[voteI_lable] = classdict.get(voteI_lable, 0) + 1 # get是字典的get方法
sort_classdict = sorted(classdict.items(), key=operator.itemgetter(1), reverse=True)
# 把结果加入result
result1.append(sort_classdict[0][0])
return result1
def draw1(group, test_x, color):
plt.scatter(group[:, 0], group[:, 1], c=lable, alpha=0.5)
plt.scatter(test_x[:, 0], test_x[:, 1], c=color, marker='*')
# plt.axis(0, 10, 0, 100)
plt.show()
# -----------------------------------------------------------------------
def evaluation_criteria(test_x, num): # 设置评估标准,划定红绿界限,用于和KNN比较,以确定混淆矩阵
result2 = []
for i in range(test_x.shape[0]):
if test_x[i][0] > num:
result2.append('green')
else:
result2.append('red')
return result2
def confusion_matrix(result1, result2): # 混淆矩阵,result1为KNN的预测结果,result2为评估标准
TP = 0 # 预测为正,实际为正
FP = 0 # 预测为正,实际为负
FN = 0 # 预测为负,实际为正
TN = 0 # 预测为负,实际为负
for i in range(result1.__len__()):
if result1[i] == 'green' and result2[i] == 'green':
TP += 1
if result1[i] == 'green' and result2[i] == 'red':
FP += 1
if result1[i] == 'red' and result2[i] == 'green':
FN += 1
if result1[i] == 'red' and result2[i] == 'red':
TN += 1
if TP + FN != 0:
TPR = TP / (TP + FN)
else:
TPR = 1
if FP + TN != 0:
FPR = FP / (FP + TN)
else:
FPR = 0
result3 = [TPR, FPR]
return result3
def ROC(test_x): # 绘制ROC曲线
arrayTPR = []
arrayFRP = []
result1 = KNN(test_x, group, lable, 3) # 获得KNN的预测结果
arrayTPR.append(0)
arrayFRP.append(0)
for num in range(0, 100):
result2 = evaluation_criteria(test_x, num) # 生成评估标准
result3 = confusion_matrix(result1, result2) # 生成对应评估标准的混淆矩阵
arrayTPR.append(result3[0])
arrayFRP.append(result3[1])
arrayTPR.append(1)
arrayFRP.append(1)
draw2(arrayFRP, arrayTPR)
def draw2(FRP, TPR): # 绘制ROC曲线
plt.title("ROC", fontsize=14, color='k') # 设置图表标题
# plt.axis([-0.5, 1.5, -0.5, 1.5]) # 设置画布大小
line_KNN, = plt.plot(FRP[:], TPR[:], marker='d', markersize=5, color='blue', linestyle="-", linewidth=1)
plt.legend(handles=[line_KNN], labels=['KNN'], loc='lower right') # 添加图例
plt.plot([0, 1], [0, 1], color='red', linestyle='--') # 绘制对角线
plt.show()
if __name__ == '__main__':
group, lable = DataSet()
test_x = TestData()
print(test_x)
result1 = KNN(test_x, group, lable, 3)
print('输入数据所对应的类别1是:{}'.format(result1))
print('输入数据所对应的类别2是:{}'.format(evaluation_criteria(test_x, 0)))
ROC(test_x)
# draw1(group, test_x, result1)
以上代码完成了从数据准备到绘制ROC曲线的完整过程。绘制出的ROC曲线展示了模型在不同阈值下,随着假正例率的增加,真正例率能提升到何种程度。理想的ROC曲线应尽可能靠近左上角(FPR=0, TPR=1),对应的AUC值越接近1,表明模型的分类性能越好。
5.ROC曲线图:
四、总结
分类模型评估旨在客观地衡量模型在特定任务上的性能,以便了解其在新数据上的预测能力。
优点:
量化性能:评估方法提供了定量指标,
指导模型选择与优化:通过评估结果,可以确定哪个模型或哪种参数组合在特定任务上表现最优,为模型选择和参数调整提供依据。
洞察模型弱点:某些评估指标(如混淆矩阵、ROC曲线)能揭示模型在处理特定类别或阈值设定上的弱点,帮助针对性地改进模型或调整策略。
缺点:
依赖于评估指标的选择:不同评估指标侧重于模型性能的不同方面,选择不当可能导致对模型能力的误解。
忽略成本差异:标准评估指标通常不考虑不同类型的错误在实际应用中的成本差异。
综上所述,分类模型评估是不可或缺的模型验证环节,它提供了有价值的信息以指导模型优化和决策。然而,评估过程中应注意选择合适的指标、确保数据质量、考虑实际应用中的成本差异,并结合模型解释性需求进行综合评判。同时,应对评估计算的资源需求有所预期并合理规划。