我们在进行机器学习时需要衡量机器学习的优劣和本身模型的准确程度,比如简单的衡量数据的准确率和错误率,但是我们更关心的是模型的泛化能力的指标,即基于模型的所选的item相关性以及模型分类指标的好坏。

机器学习度量

  • error rate(错误率):把分类错误的样本数占样本总数的比例。$$E=a/m$$
  • accuracy(精确度):分类正确的样本数占样本总数的比例。$$acc=1-E$$
  • **training error(训练误差):**学习器在训练集上的误差。
  • **generalization error(泛华误差):**在新样本上的误差。

在机器学习中由很多机器学习算法,那么如何选择这些算法和模型,如何评估这些算法和模型,评估模型的算法和准确率的方式很多,我们依次来介绍一下几个常用的指标。TP、TN、FP、FN、Acc、Recall、F1、ROC和ROI

各种机器学习衡量指标

Accuracy、Precision、Recall和F1-Score

混淆矩阵是按照预测分类和实际分类的类别对比,如下图所示: 混淆矩阵 如上表所示,行表示预测的label值,列表示真实label值。TP,FP,FN,TN分别表示如下意思:

  • TP(true positive):表示样本的真实类别为正,最后预测得到的结果也为正
  • FP(false positive):表示样本的真实类别为负,最后预测得到的结果却为正
  • FN(false negative):表示样本的真实类别为正,最后预测得到的结果却为负
  • TN(true negative):表示样本的真实类别为负,最后预测得到的结果也为负

$$ Accuracy = \frac{TP+TN}{TP+FP+TN+FN} $$ $$ Precision = \frac{TP}{TP+FP} $$ $$ Recall = \frac{TP}{TP+FN} $$ $$ SP = \frac{TN}{TN + FP}\
$$

  • Accuracy:表示预测结果的精确度,预测正确的样本数除以总样本数。
  • Precision,准确率,表示预测结果中,预测为正样本的样本中,正确预测为正样本的概率;
  • Recall,召回率,表示在原始样本的正样本中,最后被正确预测为正样本的概率;
  • Specificity,常常称作特异性,它研究的样本集是原始样本中的负样本,表示的是在这些负样本中最后被正确预测为负样本的概率。

在实际当中,我们往往希望得到的precision和recall都比较高,比如当FN和FP等于0的时候,他们的值都等于1。但是,它们往往在某种情况下是互斥的。例如,有50个正样本,50个负样本,结果全部预测为正样本,那么TP=50,FP=50,TN=0,FN=0,按照上面的公式计算,可以得到正样本的recall却为1,precision却为0.5.所以需要一种折衷的方式,因此就有了F1-score。

$$ F1-score = \frac{2\times recall \times precision}{ recall + precision} $$

F1-score表示的是precision和recall的调和平均评估指标. 另外还有一个指标,即MCC,该指标对于不均衡数据集的评估非常有效,公式如下:

$$ MCC=\frac{(TP \times TN)-(FP \times FN)}{\sqrt{(TP+FP)\times(TP+FN)\times(TN+FP)\times(TN+FN)}} $$

ROC和AUC

ROC(receiver operating characteristic),平面的横坐标是false positive rate(FPR)假阳率,纵坐标是true positive rate(TPR)真阳率。ROC计算过程如下: 1.首先每个样本都需要有一个label值,并且还需要一个预测的score值(取值0到1); 2.然后按这个score对样本由大到小进行排序,假设这些数据位于表格中的一列,从上到下依次降序; 3.现在从上到下按照样本点的取值进行划分,位于分界点上面的我们把它归为预测为正样本,位于分界点下面的归为负样本; 4.分别计算出此时的TPR(Recall)=TP/P和FPR(1-SP)=FP/N,然后在图中绘制(FPR, TPR)点。 5.从上往下逐个样本计算,最后会得到一条光滑的曲线 。 ROC 曲线 图片来自参考文献[5] AUC计算 AUC(area under the curve)就是ROC曲线下方的面积,取值在0.5到1之间,因为随机猜测得到额AUC就是0.5。面积如下图所示,阴影部分即为AUC面积: AUC面积图解—图片来自(参考文献5)

IOU和ROI

上面大多数针对分类准确性的性能评估,在机器视觉领域同样也有相应的评估指标。 1.IoU (Intersection over Union),交集并集比 2.ROI (region of interest) , 感兴趣区域 在讲这两个概念前,不得不聊聊目标检测.如下图: 目标检测 在计算机中,传统目标检测方法大致分为如下三步: 1.区域选择 为了对目标的位置进行定位。由于目标可能出现在图像的任何位置,而且目标的大小、长宽比例也不确定,所以最初采用滑动窗口的策略对整幅图像进行遍历,而且需要设置不同的尺度,不同的长宽比。这种穷举的策略虽然包含了目标所有可能出现的位置,但是缺点也是显而易见的:时间复杂度太高,产生冗余窗口太多,这也严重影响后续特征提取和分类的速度和性能。(实际上由于受到时间复杂度的问题,滑动窗口的长宽比一般都是固定的设置几个,所以对于长宽比浮动较大的多类别目标检测,即便是滑动窗口遍历也不能得到很好的区域) 2.特征提取 由于目标的形态多样性,光照变化多样性,背景多样性等因素使得设计一个鲁棒的特征并不是那么容易。然而提取特征的好坏直接影响到分类的准确性。(这个阶段常用的特征有SIFT、HOG等)。 3.分类器 主要有SVM, Adaboost等。 总结:传统目标检测存在的两个主要问题:一个是基于滑动窗口的区域选择策略没有针对性,时间复杂度高,窗口冗余;二是手工设计的特征对于多样性的变化并没有很好的鲁棒性。深度学习特别是CNN的出现使得上述第2,3步可以合并在一起做。 目标检测的训练集图片准备完成后,真正的评价函数是IoU(Intersection over Union)。为什么要用交集与并集的比值呢? 来自:https://www.pyimagesearch.com/2016/11/07/intersection-over-union-iou-for-object-detection/ 上图绿色框是真实感兴趣区域,红色框是预测区域,这种情况下交集确实是最大的,但是红色框并不能准确预测物体位置。因为预测区域总是试图覆盖目标物体而不是正好预测物体位置。这时如果我们能除以一个并集的大小,就可以规避这种问题: 来自:https://www.pyimagesearch.com/2016/11/07/intersection-over-union-iou-for-object-detection/ 这样,如果我们控制并集不要让并集太大,对准确预测是有益的。 下面是wiki上的计算各种指标 AUC ROC

实践

宏平均比微平均更合理,但也不是说微平均一无是处,具体使用哪种评测机制,还是要取决于数据集中样本分布 宏平均(Macro-averaging),是先对每一个类统计指标值,然后在对所有类求算术平均值。 微平均(Micro-averaging),是对数据集中的每一个实例不分类别进行统计建立全局混淆矩阵,然后计算相应指标。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import numpy as np
from sklearn.metrics import accuracy_score
from sklearn.metrics import precision_recall_curve
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
from sklearn.metrics import cohen_kappa_score
from sklearn.metrics import roc_auc_score
from sklearn.metrics import roc_curve

#import data
y_pred = [0, 2, 1, 3,1,1,1,3,2]
y_true = [0, 1, 1, 3,1,2,1,3,3]
print("accuracy==",accuracy_score(y_pred=y_pred,y_true=y_true))
print("accuracy size==",accuracy_score(y_pred=y_pred,y_true=y_true,normalize=False))
accuracy== 0.6666666666666666
accuracy size== 6

#计算精准率和召回率,宏平均比微平均更合理,但也不是说微平均一无是处,具体使用哪种评测机制,还是要取决于数据集中样本分布。
# 宏平均(Macro-averaging),是先对每一个类统计指标值,然后在对所有类求算术平均值。 
# 微平均(Micro-averaging),是对数据集中的每一个实例不分类别进行统计建立全局混淆矩阵,然后计算相应指标。
#print("precision==",precision_score(y_pred=y_pred,y_true=y_true))只针对于二元分类
print("micro precision==",precision_score(y_pred=y_pred,y_true=y_true,average='micro'))
print("macro precision==",precision_score(y_pred=y_pred,y_true=y_true,average='macro'))
micro precision== 0.6666666666666666
macro precision== 0.6875

#print("recall==",recall_score(y_pred=y_pred,y_true=y_true))只针对于二元分类
print("micro recall==",recall_score(y_pred=y_pred,y_true=y_true,average='micro'))
print("macro recall==",recall_score(y_pred=y_pred,y_true=y_true,average='macro'))
micro recall== 0.6666666666666666
macro recall== 0.6041666666666666
#计算f1_score
#print("f1_score==",f1_score(y_pred=y_pred,y_true=y_true))
print("weighted f1_score==",f1_score(y_pred=y_pred,y_true=y_true,average="weighted"))
print("micro f1_score==",f1_score(y_pred=y_pred,y_true=y_true,average="micro"))
print("macro f1_score==",f1_score(y_pred=y_pred,y_true=y_true,average="macro"))
weighted f1_score== 0.7111111111111111
micro f1_score== 0.6666666666666666
macro f1_score== 0.6375
#查看混淆矩阵
print(confusion_matrix(y_pred=y_pred,y_true=y_true))
[[1 0 0 0]
 [0 3 1 0]
 [0 1 0 0]
 [0 0 1 2]]
#查看混淆矩阵报告
print(classification_report(y_pred=y_pred,y_true=y_true))
	           precision    recall  f1-score   support

          0       1.00      1.00      1.00         1
          1       0.75      0.75      0.75         4
          2       0.00      0.00      0.00         1
          3       1.00      0.67      0.80         3

avg / total       0.78      0.67      0.71         9
#可以通过kappa检验两个数据之间的相似性,kappa score是一个介于(-1, 1)之间的数. score>0.8意味着好的分类;0或更低意味着不好。
cohen_kappa_score(y1=y_pred,y2=y_true)
0.5178571428571428

我们下面看一下多分类的ROC和AUC指标和可视化,下面的例子来自于sklearn。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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

# Import some data to play with
iris = datasets.load_iris()
X = iris.data
y = iris.target

# Binarize the output
y = label_binarize(y, classes=[0, 1, 2])
n_classes = y.shape[1]

# Add noisy features to make the problem harder
random_state = np.random.RandomState(0)
n_samples, n_features = X.shape
X = np.c_[X, random_state.randn(n_samples, 200 * n_features)]

# 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)

# Compute ROC curve and ROC area for each class
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])

# Compute micro-average ROC curve and ROC area
fpr["micro"], tpr["micro"], _ = roc_curve(y_test.ravel(), y_score.ravel())
roc_auc["micro"] = auc(fpr["micro"], tpr["micro"])

# Compute macro-average ROC curve and ROC area

# First aggregate all false positive rates
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
plt.figure()
plt.plot(fpr["micro"], tpr["micro"],
         label='micro-average ROC curve (area = {0:0.2f})'
               ''.format(roc_auc["micro"]),
         color='deeppink', linestyle=':', linewidth=4)

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()

我们能看到如下图所示图片 多分类ROC和AUC可视化 关于IoU指标可以参考文献6,里面介绍的很详细。

参考文献