在机器学习领域,判断模型的好坏往往是通过评价指标来得到的。而在众多的指标中,大部分指标只能片面的反应模型的一部分性能,如果不能合理的运用,往往会得到错误的结论。下面我们通过一个小故事来开始今天的内容:
某公司希望把自己的广告针对性的定向投放给客户,为此该公司将所有客户的数据分为训练集和测试集,建立了模型,并且模型的准确率达到了95%,但是在实际过程中广告的投放还是没有针对性,这是为什么呢?
下面我们先来简单介绍几个概念。
准确率:分类正确的样本占总样本个数的比例
其中correct为正确的样本,total为总样本。
准确率是非常简单且直观的指标,但是它存在一个明显的问题,当负样本占到99%的时候,就算分类器把所有的样本都分为负样本,其准确率也高达99%。所以类别不平衡成为了影响准确率最主要的因素。现在小故事中的问题就可以迎刃而解了,公司的对于广告的针对性客户只占很少的比例,而模型测试的却是对针对性客户的准确率,所以它的准确率被无意当中放大了,解决这个问题的办法是分别计算每个类别的准确率的平均值,其公式如下:
常用的指标还有精准率,召回率,ROC等,为了把这些指标说清楚下面我们定义如下概念:
TP:真正例, FP:假正例, FN:假反例, TN:真反例。
精准率(Precision):分类正确的正样本个数占分类器判断为正样本个数的比例。
召回率(Recall):分类正确的样本个数占真正样本个数的比例。
精准率和召回率从定义上看这是一对矛盾统一的评价指标。即准确率高了召回率就会降低,因此我们经常使用P-R(Precision-Recall)曲线来评价,如下图所示:
其横坐标是召回率,纵坐标是精确率。对于某一个模型来说,P-R曲线上的一个点代表,在这个阈值下,模型将大于该阈值的结果判断为正样本,小于该阈值的样本判断为负样本,返回的结果为对应的精准率和召回率。对于上图来说当召回率接近于0时,A模型的精准率为0.9,A模型的精准率为1;而随着召回率的增加,精准率都在降低,当召回率为1是,A模型的精准率超过了B模型的精准率。所以只有通过P-R曲线的整体表现,才能够对模型进行全面的评估。
ROC曲线
ROC(Receiver Operating Characteristic Curve)曲线的中文名字叫“受试者工作特征曲线”,其主要的分析方法就是画这条蓝色特征曲线。如下图所示:
其纵坐标为真正例率:
横坐标为假正例率:
举个例子来说,假设有10位疑似癌症的患者,其中3位为真正的癌症患者(N+=3),7位不是癌症的患者(N_=7)。医院的诊断为3位癌症患者,其中有2位是真患者(TP=2),那么TPR=2/3。对于7为非癌症患者,有一位被误诊为癌症患者(FP=1),那么FPR=1/7。那么对于医院来说,(2/3,1/7)就对应了ROC曲线上的一个点。
如何画ROC曲线
例如我们有如下二分类样本以及其预测的结果
第一个曲线左边为(0,0),看第一个样本预测也是正样本,为正样本即TP=1,所有样本中正样本的个数为10即N+=10,故TPR=TP/N+=1/10。没有预测错的正样本即FP=0,负样本总数N_=10,故FPR=FP/N_=0,对应的ROC曲线为(0,0.1),这样依次计算每个点,最终画出如下所示图像:
如何计算AUC,AUC顾名思义就是ROC曲线下方的面积,由于ROC曲线总是在y=x这条红色直线上方,故AUC的取值为[0.5,1]。
在评价模型时ROC和P-R曲线如何选择
相比P-R曲线,ROC当负样本的分布发生变化时,ROC能基本保持不变,而P-R曲线一般会发生比较剧烈的变化。在很多实际问题中,正负样本往往不平衡,所以ROC的适用性比P-R曲线更强,因而ROC曲线的使用场景也更多。如果想要直观看到模型在特定数据集上的表现,应该选择P-R曲线。
下面来看一下ROC的代码实现
import numpy as np
import matplotlib.pyplot as plt
from itertools import cycle
from sklearn import svm, datasets
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
from scipy import interp
# 加载数据
iris = datasets.load_iris()
X = iris.data
y = iris.target
# 将标签二值化
y = label_binarize(y, classes=[0, 1, 2])
# 设置种类
n_classes = y.shape[1]
# 训练模型并预测
random_state = np.random.RandomState(0)
n_samples, n_features = X.shape
# shuffle and split training and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.5,random_state=0)
# Learn to predict each class against the other
classifier = OneVsRestClassifier(svm.SVC(kernel='linear', probability=True,
random_state=random_state))
y_score = classifier.fit(X_train, y_train).decision_function(X_test)
# 计算每一类的ROC
fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(n_classes):
fpr[i], tpr[i], _ = roc_curve(y_test[:, i], y_score[:, i])
roc_auc[i] = auc(fpr[i], tpr[i])
all_fpr = np.unique(np.concatenate([fpr[i] for i in range(n_classes)]))
# Then interpolate all ROC curves at this points
mean_tpr = np.zeros_like(all_fpr)
for i in range(n_classes):
mean_tpr += interp(all_fpr, fpr[i], tpr[i])
# Finally average it and compute AUC
mean_tpr /= n_classes
fpr["macro"] = all_fpr
tpr["macro"] = mean_tpr
roc_auc["macro"] = auc(fpr["macro"], tpr["macro"])
# Plot all ROC curves
lw=2
plt.figure()
plt.plot(fpr["macro"], tpr["macro"],
label='macro-average ROC curve (area = {0:0.2f})'
''.format(roc_auc["macro"]),
color='navy', linestyle=':', linewidth=4)
colors = cycle(['aqua', 'darkorange', 'cornflowerblue'])
for i, color in zip(range(n_classes), colors):
plt.plot(fpr[i], tpr[i], color=color, lw=lw,
label='ROC curve of class {0} (area = {1:0.2f})'
''.format(i, roc_auc[i]))
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()
输出的图像为:
参考文章:https://blog.csdn.net/xyz1584172808/article/details/81839230
更多内容请扫描下方二维码关注小编公众号:程序员大管。