1. 混淆矩阵
要想掌握了解分类算法的各类评价指标,首先要知道混淆矩阵的计算方法,因为所有的评价指标都是基于混淆矩阵推导演算而得,下表即为混淆矩阵。
真实情况 | 预测结果 | |
0 反例 Negative | 1 正例 Positive | |
0 反例 Negative | TN 真反例 True Negative | FP 假正例 False Positive |
1 正例 Negative | FN 假反例 False Negative | TP 真正例 True Positive |
2. 准确率、错误率
准确率( Accuracy)正确率,又叫精度,分类正确的样本数占样本总数的比例,综合考虑正反分类结果,计算整体的正确率。
错误率,分类错误的样本占样本总数的比例,综合考虑正反分类结果,计算整体的错误率,和正确率相加之和等于1
3. 精准率、召回率
精准率(Precision)又叫查准率,它是针对预测结果而言的,它的含义是在所有被预测为正的样本中实际为正的样本的概率,意思就是在预测为正样本的结果中,我们有多少把握可以预测正确。
召回率(Recall)又叫查全率,它是针对原样本而言的,它的含义是在实际为正的样本中被预测为正样本的概率,意思就是在预测为正样本的结果中,我们有多少把握把所有正样本都找出来。
为了更好让读者理解精准率和召回率,笔者用Visio画了如下示意图以便理解。左边矩形框图中的绿色小球表示所有真实的反例,右边矩形框图中红色小球表示所有真实的正例。我们有一个分类模型,即利用橙色大圆饼圈住所有正例的小球。但由于模型不够完美,橙色大圆饼无法精确圈住所有正例(红色小球),也无法保证圈住的就都是正例。
如下图所示,橙色大圆饼一共圈住了5个小球,其中只有3个小球是正例,2个小球是反例,圆饼中红色小球的个数与圆饼中小球的总数之比即是精准率。比如股票预测模型就是一个对精准率要求较高的模型,模型不在乎把明天所有涨停板的股票(正例)都预测出来,但希望预测的股票全都会涨。
即希望橙色大圆饼中全都是红色小球,不贪多,宁缺毋滥,即使矩形框中一共有4个红色小球,哪怕是只圈住一个红色小球,这个模型在股市预测中也是极有用处的。
如下图所示,橙色大饼圈中红色小球的个数占所有红色小球个数的比例即为召回率,可以这样理解,样本中一共有4个正例,模型召唤回来三个,还剩一个跑掉了,这就是召回率。比如癌症预测就是一个对召回率要求比较高的模型,宁可错杀一千,不可漏网一人,如果漏掉真的癌症患者,可能会让这为患者错失治疗良机,后果很严重,但及时把正常人误判为癌症,也可以通过后期进一步的检查确诊。
即希望橙色大圆饼中把样本中所有的红色小球都圈住,不怕多,即使圈错了也能接受,但一定要把所有正例召唤回来。
基于sklearn自带的load_digits数字识别数据集为例,此数据集为多分类数据集,这里将数据集处理为二分类问题,等于9的数据集作为一个分类,其他的作为一个分类,这样计算得的混淆矩阵及相关指标,代码如下所示:
import numpy as np
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import confusion_matrix
from sklearn.metrics import f1_score
from sklearn.metrics import accuracy_score
from sklearn.metrics import roc_auc_score
from sklearn.metrics import roc_curve
import matplotlib.pyplot as plt
X_train, X_test, y_train, y_test = 0, 0, 0, 0
def dataInit(type="binary"):
global X_train, X_test, y_train, y_test
digits = datasets.load_digits()
X = digits.data
y = digits.target.copy()
if type == 'binary':
y[digits.target == 9] = 1
y[digits.target != 9] = 0
elif type == "multiclass":
y = y
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
log_reg = LogisticRegression(max_iter=10000)
log_reg.fit(X_train, y_train)
return log_reg
# confusion_matrix 混淆矩阵 及 相关推演出来的指标
def matrix_precision_accuracy_recall_f1():
log_reg = dataInit(type="binary")
y_predict = log_reg.predict(X_test)
matrix = confusion_matrix(y_test, y_predict)
accuracyScore = accuracy_score(y_test, y_predict)
precisionScore = precision_score(y_test, y_predict)
recallScore = recall_score(y_test, y_predict)
f1Score = f1_score(y_test, y_predict)
print("accuracy_score = {}".format(accuracyScore))
print("confusion_matrix = {}".format(matrix))
print("precision_score = {}".format(precisionScore))
print("recall_score = {}".format(recallScore))
print("f1_score = {}".format(f1Score))
if __name__ == "__main__":
matrix_precision_accuracy_recall_f1()
# MyselfPRCurve()
# PRCurve()
# ROCCurve()
# Matrix_in_Multiclass()
4 PR曲线、F1度量、
通过左右移动分类算法的决策边界,可获得不同的精准率和召回率,其中决策边界值为:
这样我们就得到了新的超参数threshold,从而影响分类模型对样本的分类结果。以决策边界值threshold为横坐标,精准率及召回率为纵坐标,即可得到如下曲线图,从图中可以看出,精准率和召回率是相辅相成,此消彼长的,可以根据实际应用场景,调节超参数threshold,从而获得想要的精准率和召回率。
为了综合考虑精准率和召回率两个指标,以精准率为横坐标,召回率为纵坐标,绘制如下曲线图,如果曲线图与横纵坐标围城的面积越大,即可认为模型综合性能越强。
这个面积计算相对复杂,我们可通过F1度量指标获得综合考虑值。
F1度量:综合考虑精准率和召回率的一个性能指标,通过求二者的调和平均而得:
PR曲线及F1计算可通过sklearn自带的方法获得,输入测试样本结果值y_test,以及测试样本x_test的决策值decision_scores,可通过precision_recall_curve函数,自动得到thresholds以及对应的precisions,和recalls,其中thresholds是以decision_scores值域为边界,以0.1步长遍历得到的数组。
def PRCurve(): # Precision and Recall Curve
from sklearn.metrics import precision_recall_curve
log_reg = dataInit(type='binary')
decision_scores = log_reg.decision_function(X_test)
precisions, recalls, thresholds = precision_recall_curve(y_test, decision_scores)
plt.plot(thresholds, precisions[:-1]) # thresholds 代表不同的分类边界线
plt.plot(thresholds, recalls[:-1])
plt.xlabel("thresholds")
plt.ylabel("precisions and recalls")
plt.legend(['recalls', 'precisions'])
plt.show()
plt.plot(precisions, recalls) # x轴 = precisions y轴 = recalls
plt.xlabel("precisions")
plt.ylabel("recalls")
plt.show()
如果读者感兴趣,也可通过decision_scores手动求得thresholds数组,对x_test中的decision_scores 与thresholds进行比较得到分类结果,然后根据精准率和召回率的方法分别求thresholds对应下的值:
y_predict = np.array(decision_scores >= thresholds, dtype='int')
整个过程其计算代码如下:
def MyselfPRCurve():
precisionScore = []
recallScore = []
thresholds = []
log_reg = dataInit(type='binary')
decisionScores = log_reg.decision_function(X_test)
for threshold in np.arange(min(decisionScores), max(decisionScores), 0.1):
y_predict = np.array(decisionScores >= threshold, dtype='int')
precisionScore.append(precision_score(y_test, y_predict))
recallScore.append(recall_score(y_test, y_predict))
thresholds.append(threshold)
plt.plot(thresholds, precisionScore) # thresholds 代表不同的分类边界线
plt.plot(thresholds, recallScore)
plt.xlabel("thresholds")
plt.ylabel("precisions and recalls")
plt.legend(['recalls', 'precisions'])
plt.show()
plt.plot(precisionScore, recallScore) # x轴 = precisions y轴 = recalls
plt.xlabel("precisions")
plt.ylabel("recalls")
plt.show()
5. TPR、FPR
除了以上指标外,还有真真正例率和假正例率的评判,这两个指标相对少用,其定义如下:
真正例率(True Positive Rate),反应的是真正例占样本中所有正例的比例:
假正例率(False Positive Rate),反应的是假正例在样本中所有反例的比例:
6. ROC、AUC
不断调整thresholds超参数,得到一系列TPR和FPR,由真正例率和假正例率这两个指标分别作为纵坐标和横坐标绘制出的曲线叫ROC曲线(Receiver Operating Characteristic )受试者工作特征曲线,ROC曲线与横纵坐标围绕出来的面积AUC(Area Under ROC Curve) 越大,其模型越优秀。
其代码实现如下所示:
# Receiver Operating Characteristic 受试者工作特征曲线
def ROCCurve():
log_reg = dataInit(type='binary')
decision_scores = log_reg.decision_function(X_test)
fprs, tprs, thresholds = roc_curve(y_test, decision_scores)
plt.plot(fprs, tprs) # x轴 = FPR(假正例率) y轴 = TPR(真正例率)
plt.xlabel("FPR")
plt.ylabel("TPR")
plt.show()
auc = roc_auc_score(y_test, decision_scores) # AUC(Area Under ROC Curve) ROC曲线围绕出来的面积 值域(0,1)
print("roc_auc_score = {}".format(auc))
7. 多分类的混淆矩阵
混淆矩阵同样支持多分类算法,通过多分类混淆矩阵可直观迅速的得出判别误差较大的两个类别,从而针对性的对算法进行优化,可以通过matshow函数将矩阵转换为图形,转换为图形前为了对误差项针对性的观察,对混淆矩阵进行预处理,将非误差项(对角线的数值)置零,对误差项求比例值,具体代码实现如下:
# Confusion Matrix in Multiclass Classification 多分类混淆矩阵
def Matrix_in_Multiclass():
log_reg = dataInit(type='multiclass')
y_predict = log_reg.predict(X_test)
matrix = confusion_matrix(y_test, y_predict)
print("Confusion Matrix in Multiclass Classification = {}".format(matrix))
row_sums = np.sum(matrix, axis=1) # 每行求和得到列向量,即每个类别真值的数量
err_matrix = matrix / row_sums # 求相对真值数量的百分比
np.fill_diagonal(err_matrix, 0) # 对角线预测正确的值忽略置零
plt.matshow(err_matrix, cmap=plt.cm.gray)
plt.show()
8. 总结
本文以sklearn自带的load_digits数字识别数据集为例,讲解了混淆矩阵、准确率、错误率、精准率、召回率、PR曲线、F1度量、TPR、FPR、ROC曲线、AUC等分类算法的评判指标计算公式和基于sklearn的代码计算方法。