我们在用机器学习、深度学习建模、训练模型过程中,需要对我们模型进行评估、评价,并依据评估结果决策下一步工作策略,常用的评估指标有准确率、精准率、召回率、F1分数、ROC、AUC、MAE、MSE等等,本文将结合SKlearn的metrics所封装的函数,重点围绕多分类问题实践评估指标。
在机器学习、深度学习、数据挖掘领域,工业界往往会根据实际的业务场景拟定相应的业务指标。本文主要是分享分类问题模型的评价指标,对于分类问题,实际应用中往往会遇到多分类情况。
其实,分类问题评估指标是适合多分类情况的,只是举例往往是二分类的,本文虽然介绍指标时是以二分类开始,但是公式可以拓展到多分类。
分类问题评估指标:
回归问题评估指标:
优化目标指标:
混淆矩阵(confusion matrix)也称误差矩阵,是表示精度评价的一种标准格式,用 n n n行 n n n列的矩阵形式来表示。在人工智能中,特别用于监督学习衡量的是一个分类器分类的准确程度,比较分类结果和实际测得值,可以把分类结果的精度显示在一个混淆矩阵里面。
混淆矩阵适用于多分类器的问题,本文为了让读者理解更加容易,以手写数字“5”分类识别二元分类的混淆矩阵为例说明。
如果我们想知道类别之间相互误分的情况,查看是否有特定的类别相互混淆,就可以用混淆矩阵画出分类的详细预测结果。对于包含多个类别的任务,可以很清晰的反映各类别之间的错分概率。
虽然准确率可以判断总的正确率,但是在样本不平衡 的情况下,并不能作为很好的指标来衡量结果。举个简单的例子,比如在一个总样本中,正样本占 90%,负样本占 10%,样本是严重不平衡的。对于这种情况,我们只需要将全部样本预测为正样本即可得到 90% 的高准确率,但实际上我们并没有很用心的分类,只是随便无脑一分而已。这就说明了:由于样本不平衡的问题,导致了得到的高准确率结果含有很大的水分。即如果样本不平衡,准确率就会失效。
ROC曲线是Receiver Operating Characteristic Curve的简称,中文名为“受试者工作特征曲线”。
ROC曲线的横坐标为假阳性率(False Positive Rate,FPR);纵坐标为真阳性率(True Positive Rate,TPR)。FPR和TPR的计算方法分别为:
ROC是由点(TPR,FPR)组成的曲线,AUC就是ROC的面积。
一般来说,AUC越大越好;如果TPR越高,同时FPR越低(即ROC曲线越陡),那么模型的性能就越好;ROC是光滑的,那么基本可以判断没有太大的overfitting。
为什么使用 ROC 曲线
既然已经这么多评价标准,为什么还要使用 ROC 和 AUC 呢?因为 ROC 曲线有个很好的特性:当测试集中的正负样本的分布变化的时候,ROC 曲线能够保持不变。在实际的数据集中经常会出现类不平衡(class imbalance)现象,即负样本比正样本多很多(或者相反),而且测试数据中的正负样本的分布也可能随着时间变化。
sklearn.metrics中包含了许多模型评估指标,包括:分类、回归、聚类等模型评估工具。官方API为:sklearn.metrics: Metrics。
# 计算准确率
accuracy = accuracy_score(self.y_test, predictions)
precision = precision_score(self.y_test.values, np.array(predictions),average='macro')
print('precision Score: %.2f%%' % (precision*100.0))
recall = recall_score(self.y_test, predictions)
报错:
ValueError: Target is multiclass but average='binary'.
Please choose another average setting, one of [None, 'micro', 'macro', 'weighted'].
recall = recall_score(self.y_test.values, np.array(predictions),average='macro')
print('Recall Score: %.2f%%' % (recall*100.0))
Y_pred = clf.predict(X_test)
# 随机森林的AUC值
forest_auc = roc_auc_score(Y_test, Y_pred)
auc = roc_auc_score(self.y_test, predictions)
报错:
ValueError: multi_class must be in ('ovo', 'ovr')
修改代码:
recall = recall_score(self.y_test, predictions,average='micro')
auc = roc_auc_score(self.y_test, predictions ,multi_class='ovo',average='macro')
下面代码参考自sklearn样例代码“Compute macro-average ROC curve and ROC area”:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from itertools import cycle
from sklearn.metrics import roc_curve, auc
from scipy import interp
class Multi_class_evaluation(object):
# 输入原始值,预测值,分类数量
def __init__(self, y, y_pred, n_class=2, flag=None):
self.n_class = n_class
self.flag = flag
# 构造数据矩阵n*分类数量
def datas():
cols_name = []
for i in range(self.n_class):
cols_name.append('v'+str(i))
def f(v):
vv = []
for i in range(self.n_class):
if v==i:
vv.append(1)
else:
vv.append(0)
return pd.Series(vv)
self.y = pd.DataFrame()
self.y[cols_name] = y[self.flag].apply(lambda x:f(x))
datas()
self.y = self.y.to_numpy()
self.y_pred = y_pred
# 计算ROC和AUC
def calculation_ROC_AUC(self):
# Compute ROC curve and ROC area for each class
self.fpr = dict()
self.tpr = dict()
self.roc_auc = dict()
for i in range(self.n_class):
self.fpr[i], self.tpr[i], _ = roc_curve(self.y[:, i], self.y_pred[:, i])
self.roc_auc[i] = auc(self.fpr[i], self.tpr[i])
# Compute micro-average ROC curve and ROC area
self.fpr["micro"], self.tpr["micro"], _ = roc_curve(self.y.ravel(), self.y_pred.ravel())
self.roc_auc["micro"] = auc(self.fpr["micro"], self.tpr["micro"])
#默认是多分类
def draw_ROC(self,multi_class=None):
# First aggregate all false positive rates
if multi_class==None:
all_fpr = np.unique(np.concatenate([self.fpr[i] for i in range(self.n_class)]))
# Then interpolate all ROC curves at this points
mean_tpr = np.zeros_like(all_fpr)
for i in range(self.n_class):
mean_tpr += interp(all_fpr, self.fpr[i], self.tpr[i])
# Finally average it and compute AUC
mean_tpr /= self.n_class
self.fpr["macro"] = all_fpr
self.tpr["macro"] = mean_tpr
self.roc_auc["macro"] = auc(self.fpr["macro"], self.tpr["macro"])
# Plot all ROC curves
plt.figure()
lw=2 #折线宽度
plt.plot(self.fpr["micro"], self.tpr["micro"],
label='micro-average ROC curve (area = {0:0.4f})'
''.format(self.roc_auc["micro"]),
color='deeppink', linestyle=':', linewidth=4)
plt.plot(self.fpr["macro"], self.tpr["macro"],
label='macro-average ROC curve (area = {0:0.4f})'
''.format(self.roc_auc["macro"]),
color='navy', linestyle=':', linewidth=4)
colors = cycle(['aqua', 'darkorange', 'cornflowerblue'])
for i, color in zip(range(self.n_class), colors):
plt.plot(self.fpr[i], self.tpr[i], color=color, lw=lw,
label='ROC curve of class {0} (area = {1:0.4f})'
''.format(i, self.roc_auc[i]))
else:
plt.figure()
lw=2 #折线宽度
plt.plot(self.fpr[multi_class], self.tpr[multi_class],
label='ROC curve of class {0} (area = {1:0.4f})'
''.format(multi_class, self.roc_auc[multi_class]),
color='deeppink')
plt.plot([0, 1], [0, 1], 'k--', lw=lw)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Some extension of Receiver operating characteristic to multi-class')
plt.legend(loc="lower right")
plt.show()
ROC曲线的特征是Y轴上的真阳性率和X轴上的假阳性率。这意味着图的左上角是“理想”点——假阳性率为零,真阳性率为一。这不太现实,但它确实意味着曲线下的较大面积(AUC)通常更好。
ROC曲线的“陡度”也很重要,因为它是理想的最大化真阳性率,同时最小化假阳性率。
ROC曲线通常用于二值分类来研究分类器的输出。为了将ROC曲线和ROC区域扩展到多标签分类,需要对输出进行二值化。每个标签可以绘制一条ROC曲线,但也可以通过将标签指标矩阵的每个元素视为二进制预测(微平均)来绘制ROC曲线。
多标签分类的另一种评估方法是宏平均法,它赋予每个标签的分类同等的权重。
客户流失预测分为四个分类:流失、濒临流失、不活跃、活跃,通过XGBoost多分类,代码片段如下:
from PredictionModel import Multi_class_evaluation
......
y_pred=model.predict(xgb.DMatrix(self.x_test))
yprob = np.argmax(y_pred, axis=1) # return the index of the biggest pro
predictions = [round(value) for value in yprob]
# 计算准确率
accuracy = accuracy_score(self.y_test, predictions)
print("Accuracy: %.2f%%" % (accuracy * 100.0))
Mce = Multi_class_evaluation.Multi_class_evaluation(self.y_test,y_pred,n_class=4,flag='flag1')
Mce.calculation_ROC_AUC()
Mce.draw_ROC()
# 画客户流失(分类0,1,2,3中的1)
Mce.draw_ROC(multi_class=1)
y, y_ =Mce.y, Mce.y_pred
precision = precision_score(self.y_test.values, np.array(predictions),average='macro')
print('precision Score: %.2f%%' % (precision*100.0))
recall = recall_score(self.y_test.values, np.array(predictions),average='macro')
print('Recall Score: %.2f%%' % (recall*100.0))
auc = roc_auc_score(y, y_ ,multi_class='ovo',average='macro')
print('Roc Auc Score: %.2f%%' % (auc*100.0))
Accuracy: 97.93%
precision Score: 91.15%
Recall Score: 89.39%
Roc Auc Score: 99.76%
客户流失预测四个分类,分别绘制流失、濒临流失、不活跃、活跃的ROC图。
我们通常倾向于使用准确率(Acc),易于理解和沟通,但是它不是完成任务的最佳工具!在实际工程中,不平衡多分类更为常见,则召回率、精准度等度量指标较更为适合,也可以逐个分类分析。
统计学为我们提供了计算这些指标的形式化定义和方程。数据科学是关于寻找解决问题的正确工具的学科,而且在开发分类模型时,我们更需要超越准确率(accuracy)的单一指标,根据业务变换灵活运用召回率、精准度、F1 score 和 ROC 曲线评估分类模型。现在我们知道如何使用更聪明的衡量指标!
对于软件开发测试环节,灵活运用模型评估、评价技术,将助力AI更顺利的落地实施。
编者水平有限,欢迎反馈讨论。
参考:
1.《牢记分类指标:准确率、精确率、召回率、F1 score以及ROC》 简书 ,MiracleJQ ,2018年8月
2.《准确率,召回率,F1 值、ROC,AUC、mse,mape评价指标》 CSDN博客 ,雪伦_ ,2016年6月
3.《【解决问题】python编译报错 Target is multiclass but average=‘binary’. Please choose another average setting》 CSDN博客 ,君琴 ,2020年5月
4.《多分类f1分数_一文看懂分类模型的评估指标:准确率、精准率、召回率、F1等…》 CSDN博客 ,遇见高中生,2020年12月
5.《sklearn下对于二分类和多类分类问题的评估方法总结》 CSDN博客 ,Clark_Xu , 2019年8月
6.《Receiver Operating Characteristic (ROC)》scikit-learn 0.24.2 API ,2021年4月
7.《机器学习中的评价指标(一)-Accuracy、precision、Recall、F1 Score、ROC Curve、PR Curve、AUC》 CSDN博客 , faithmy509 ,2018年7月
8.《深度学习评价指标简要综述》 知乎 ,Error ,2020年8月