1 回归
评价回归模型,均方误差MSE最常用了:$1/m\sum^m_{i=1}(f(x_i)-y_i)^2$,衡量了回归结果和实际结果之间的整体误差。
# sklearn
metrics.mean_squared_error(y_true, y_pred)
# tensorflow
tf.metrics.mean_squared_error(y_true, y_pred)
# 或手动算
tf.reduce_mean(tf.square(y_true, y_pred))
2 分类问题
2.1 混淆矩阵
对于分类问题,可以通过混淆矩阵计算详细的评估指标
实际 | 预测 | ||
---|---|---|---|
正例 | 负例 | ||
正例 | 真正例TP | 假反例FN | |
负例 | 假正例FP | 真反例TN |
注意上述是二分类时的情况。多分类时,混淆矩阵是一个类别数x类别数
的矩阵,列是预测标签,行是实际标签。该混淆矩阵的元素a_ij含义是将本是j类的样本分到了i类里的数量,当i=j时,即对角线上的元素对应的数量才是正确的预测。
sklearn中计算混淆矩阵的API为
from sklearn.metrics import confusion_matrix
# y_pred是预测标签,下同
confusion_matrix(y_true=y_true, y_pred=y_pred)
tensorflow中混淆矩阵的API为
tf.confusion_matrix(
labels,
predictions,
num_classes=None, # 不指定类别数量就取数据或预测标签中最大值+1
dtype=tf.int32,
name=None,
weights=None
)
有了混淆矩阵,就可以进一步计算详细的评估指标。在实际中,一般不需要特地计算混淆矩阵。
2.2 精度accuracy
精度accuracy是分类正确的数量占样本总数的比例。这个指标其实不需要混淆矩阵就可以计算,用混淆矩阵计算的话,精度就是对角线值的和/总数。对二分类即(TP+TN)/(TP+FP+FN+TN)
。
精度的问题是对分布不均衡的数据,大类别会主导计算。平均精度是对每个类单独计算精度,然后取平均,以解决大类别主导精度计算的问题。然而因为小类别数据量少,相应的精度的方差会很大。
sklearn中的API为:
from sklearn.metrics import accuracy_score
accuracy_score(y_true=y_true, y_pred=y_pred)
# 平均精度
from sklearn.metrics import average_precision_score
使用tensorflow的API计算精度需要稍微费一点功夫。因为损失计算的原因,softmax会在计算损失的时候和交叉熵一起算,所以一般多分类NN最后一层输出是类别数量长度的序列,其中的最大值对应的index就是所属的分类。
# tf.argmax 取最大值的index,即计算分类结果
# tf.equal 对比预测分类是否和真实分类相同,得到一串布尔值
correct_prediction = tf.equal(tf.argmax(y_conv,1),tf.argmax(y,1))
# tf.cast 将布尔值转化为浮点数
# tf.reduce_mean 计算平均值
# 该平均值就是正确分类所占的百分比,即精度
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
# 除了像上边那样自己写acc,也可以在得到最终预测结果predictions之后直接调用tf.metrics计算,labels是真实结果(下同)
tf.metrics.accuracy(labels, predictions)
2.3 查准率precision
查准率precision:P=TP/(TP+FP),预测出来的正例中有多少是真正的正例,又叫查准率
precision的翻译太多样了,如准确率、精准率等等,甚至和accuracy重复而无法区分。因此这里使用“查准率”这个翻译
2.4 查全率recall
查全率recall:R=TP/(TP+FN),真正的正例有多少被分到了正例里,又叫召回率
2.5 F分数f-score
结合了查准率和查全率的指标,F1-score为二者的调和平均数:2*precision*recall/(precision+recall)
为了更明确评估过程中更看重查准率还是查全率,F-分数更通用的形式为加权调和平均$F_\beta$,其中$\beta$为查全率与查准率的权重比
$$
F_\beta=(1+\beta^2)\frac{precision\times recall}{\beta^2 precision+recall}
$$
2.6 接受者工作特征ROC
- 真正例比率TPR:TP/(TP+FN),和查全率的计算方法相同
- 假正例比率FPR:FP/(FP+TN)
ROC曲线描绘了TPR-FPR的变化关系。但混淆矩阵得到之后,只能得到一组TPR-FPR。如何得到多组呢?
在分类时,输出是属于某类的概率(或评分)。一般我们定0.5作为阈值,超过就认为属于该类,否则不属于该类。这个0.5的阈值就叫做截断点。截断点发生变动时,TPR-FPR就可以形成一条曲线了。
考查TPR-FPR平面,可以找到四个特殊点和一条特殊线:
- (0,0): TP=FP=0,所有数据都预测为负例
- (0,1): FP=0, FN=0,全对,完美分类
- (1,0): TN=0, TP=0,全错,最差分类
- (1,1): TN=0,FN=0,所有数据都预测为正例
- TPR=FPR: 过原点斜率为1的直线,预测正误一半半,相当于随机猜测
左上角的(0,1)处是完美分类器,所以ROC曲线越接近左上角说明模型性能越好。ROC曲线的好处是通过TPR和FPR减小了样本分布变化对评估指标结果造成的影响。
曲线下方的面积就是AUC,可以根据AUC的值来判断ROC是否更接近左上角。
上述的precision, recall, f-score, ROC都是基于二分类而言的。对于多分类的情况,混淆矩阵更加复杂,有两种策略求得全局的上述指标:
- 宏平均macro-average。先单独计算每个分类上的各指标,然后取平均
- 微平均micro-average。先将各混淆矩阵取平均得到一个混淆矩阵,再根据这个混淆矩阵算指标
如果各类样本数量差不多,两种策略的结果差异不大。如果各类样本差异很大,结果就有较大差异。这时根据需求选择使用哪一个:
- 更关注样本数量多的类:宏平均
- 更关注样本数量少的类:微平均
查准率、查全率、F分数和ROC都是基于混淆矩阵的评估指标,这里放在一起实现。sklearn中的API:
from sklearn import metrics
# precision
metrics.precision_score(y_true, y_pred)
# recall
metrics.recall_score(y_true, y_pred)
# f1-score
metrics.f1_score(y_true, y_pred)
# ROC曲线
# scores为属于各分类的概率或评分
# i为认为是正例的分类编号(单独求第i类的FPR,TPR和截断点。如果多分类要求全部需要手动指定一遍)
fpr, tpr, thresholds = metrics.roc_curve(y, scores, pos_label=i)
# AUC
metric.auc(fpr,tpr)
# 或直接从scores计算
metrics.roc_auc_score(y_true, scores)
# precision_score, recall_score, f1_score和roc_auc_score都还可以传入参数average,设置多分类下求平均的方式,除了宏平均macro和微平均micro外,加权weighted和采样samples两种方法
# 分类报告
# 返回每个分类的precision、recall、f1-score、数量和平均值
# names是分类名称的列表,显示用
from sklearn.metrics import classification_report
classification_report(y_true, y_pred, target_names=names)
在tensorflow中的API实现:
# precision
tf.metrics.precision(labels, predictions)
# recall
tf.metrics.recall(labels, predictions)
# f1-score
# tf.metric里没有提供f-score的API,需要自己根据P,R手写,或者调用tf.contrib.metric里的API
# contrib里的参数顺序是反过来的
tf.contrib.metrics.f1_score(predictions, labels)
# ROC and AUC
# 没有ROC的API,需要自己根据tf.metrics.true_positives等先计算出TPR, FPR算
tf.metrics.auc(labels, predictions)
3 交叉验证CV
我们知道,一般机器学习的数据会分成3部分,就是所谓的留出法:
- 训练集,用来训练模型
- 验证集,用来测试训练集训练的结果,作为模型改进的参考
- 测试集,用来测试最终优化过模型的泛化能力
三份数据的比例对于小数据来说一般是8:1:1,对于大数据是98:1:1。但对于缺乏数据的情况,就需要采取K折交叉验证的方法对数据进行划分,将训练集和验证集轮着交叉训练和验证模型:
- 将数据拿出一小部分作为测试集,剩下的数据分成K份
- 其中K-1份用作测试集,剩下的1份用作验证集。训练模型
- 重复第2步K次,每次都用不同的1份数据作为验证集
- 计算K次评估指标均值,得到模型的评估
当K和数据总数相等时,叫做留一法,相当于验证集只有一个样本。训练集就更接近数据原始分布,但计算量翻K倍增加的更多了,缺乏数据时才用。
tensorflow中没有交叉验证的API,一般DL也不需要CV。sklearn中实现交叉验证的API有sklearn.model_selection.KFold(n_splits=k)
方法划分数据,但是一般用实现了划分+训练+评价一条龙的另外一个API:
# 仅数据划分,一般不太用,而是直接用下边一条龙的方法
from sklearn.model_selection import KFold
kf = KFold(n_splits=k)
# 划分、训练、评价一条龙
# clf是模型
# scoring是指定的模型评估指标
from sklearn.model_selection import cross_val_score,cross_validate
scores = cross_val_score(clf, data, labels, cv=k, scoring='f1_macro')
# cross_validate可以指定多个评估指标
scores = cross_val_score(clf, data, labels, cv=k, scoring=['precision_macro','recall_macro'])