03_Classification
文章目录
3.1 MNIST
MNIST 是一个手写数字数据集,每张图片实际上是一个实例的特征向量,共有28*28个特征,每个特征代表像素点的强度,即从0到255。如下图所示:
- 数据增广/训练集扩展
将MNIST的图片向任意方向移动一个像素,创建出四个位移后的副本,将其加入训练集,在这个扩展后的训练集上训练模型,测量准确率,模型表现甚至会更好。
3.2 训练二元分类器
实际上我们想用该数据集去训练一个二元分类器,这里就是进行识别一个手写数字是不是5,即“数字5检测器”。
我们初始选择随机梯度下降(SGD)分类器,其优势是有效处理非常大型的数据集。
from sklearn.linear_model import SGDClassifier
sgd_clf = SGDClassifier(max_iter=1000, tol=1e-3, random_state=42)
sgd_clf.fit(X_train, y_train_5)
此时我们就训练好了一个SGD分类器,下面我们评估该模型的性能。
3.3 性能测量
3.3.1 交叉验证
使用 cross_val_score()
函数来评估 SGDClassification
模型,采用K-折交叉验证法。
- K-折交叉验证法
将训练集分解成K个折叠,每次保留其中一个折叠进行预测,剩余的折叠用来训练。
from sklearn.model_selection import cross_val_score
cross_val_score(sgd_clf,
X_train,
y_train_5,
cv=3, # 3折交叉验证
scoring="accuracy")
array([0.96355, 0.93795, 0.95615])
这是基于数据集计算出来的准确率,可以看出来准确率超过了93%,但是准确率到底能不能成为我们的首要性能指标呢?答案是不能。
- Q:Accuracy不能成为首要性能指标的原因?
很简单的道理,如果训练集中只有10%的图片是5,你去预测一张图片不是5,肯定预测准确的概率很高。所以其不能作为首要性能指标,特别是处理有偏数据集时。
3.3.2 混淆矩阵
对于二元分类器来说,其混淆矩阵形式如下:
其中0表示负类,1表示正类,所以TP表示真正类,FP表示假正类,其余同理。在真正输出时混淆矩阵是以数组的形式。
from sklearn.metrics import confusion_matrix
confusion_matrix(y_train_5, y_train_pred)
array([[53057, 1522],
[ 1325, 4096]])
从上述输出结果来看,本来是5预测也是5的有4096个,本来是5预测为非5的有1522个。所以一个完美的分类器的混淆矩阵应该只在对角线上有非零值。
array([[54579, 0],
[ 0, 5421]])
3.3.3 精度和召回率
混淆矩阵能提供很多信息,但是为了使指标更简洁些,我们常用一下几个指标。
- 精度(Precision):正类预测准确率。
P r e c i s i o n = T P T P + F P Precision=\frac{TP}{TP+FP} Precision=TP+FPTP
- 召回率(Recall):正确检测正类的比率。
R e c a l l = T P T P + F N Recall=\frac{TP}{TP+FN} Recall=TP+FNTP
from sklearn.metrics import precision_score, recall_score
precision_score(y_train_5, y_train_pred)
recall_score(y_train_5, y_train_pred)
- F1-分数(F1-score):用于比较两种分类器,只有精度和召回率都很高时,F1分数才会很高。
F 1 − s c o r e = 2 1 P r e c i s i o n + 1 R e c a l l F1-score=\frac{2}{\frac{1}{Precision}+\frac{1}{Recall}} F1−score=Precision1+Recall12
from sklearn.metrics import f1_score
f1_score(y_train_5, y_train_pred)
- Q:F1分数高就一定好吗?
F1-score 对精度和召回率相近的分类器更有利,但是如果从业务视角来看,有时低精度或者低召回率并不是一件坏事。
高精度、低召回率的分类器比如检测儿童是否能观看的视频分类器,我们宁可拦截很多好视频(低召回率),但是要保证保留下来的视频都是安全的(高精度)。
高召回率、低精度的分类器比如检测小偷的分类器,我们宁可收到一些错误的警报(低精度),但是几乎所有小偷都在劫难逃(高召回率)。
3.3.4 精度/召回率权衡
SGD分类器有一个阈值等于0,每个实例都会基于决策函数计算出一个分值,如果该分值大于阈值就被判为正类,反之被判为负类。
我们可以看一下在不同阈值情况下的精度和召回率。
即阈值越高,召回率越低(只会越低),但精度通常越高,也可能有所下降。这个很好理解,比如按照某一阈值分类后,得到的被判为正类的有5,6,5,5,5,那么如果阈值变大一些,那么被判断为正类的为6,5,5,5时精度就从80%下降到75%了。
而如何选择阈值,取决于项目本身。
当有人说需要精度为99%的分类器时,你应该询问召回率是多少。
3.3.5 ROC曲线
ROC曲线经常与二元分类器一起使用,绘制的是真正类率(召回率)和假正类率的曲线,从绘制图像上来看,我们更希望分类器向着左上角离着对角线越远越好(因为对角线表示纯随机分类器,即1:1的概率,没什么意义)。
当然绘制图像会比较麻烦,还有一种方法就是测量曲线下的面积(AUC),ROC_AUC>0.5且越高通常情况下越好一些。
from sklearn.metrics import roc_auc_score
roc_auc_score(y_train_5, y_scores)
3.4 多类分类器
随机森林和朴素贝叶斯分类器可以直接处理多个类,但是支持向量机和线性分类器是严格的二元分类器,但是我们有两种策略实现多类分类的目的。
- OvR策略
比如要将0-9的数字进行多分类任务,可以训练10个分类器,每个数字一个(0检测器、1检测器…),进行分类时获取每个分类器对其的决策分数,哪个分数高就是哪类。
- OvO策略
为每一对数字训练一个二元分类器,即0-1分类器、0-2分类器…如果是识别0-0需要45个分类器,最后哪个类获胜最多就是哪个类。
具体选择哪种策略要结合具体算法,比如支持向量机在数据规模扩大时表现糟糕,因此选择OvO策略(sklearn中支持向量机自动运行OvO策略),因为在较小训练集上分别训练多个分类器比在大型数据集上训练少数分类器要快得多。但对于大多数分类器OvR策略更好一些。
# 默认使用OvO策略
from sklearn.svm import SVC
svm_clf = SVC()
svm_clf.fit(X_train, y_train)
# 强制使用OvR策略
from sklearn.svm import SVC
from sklearn.multiclass import OneVsRestClassifier
ovr_clf = OneVsRestClassifier(SVC())
ovr_clf.fit(X_train, y_train)
3.5 误差分析
假设现在已经找到一个最合适的模型,我们希望找到一些方法对其进行改进,方法之一就是分析错误类型。
比如可视化一个0-9分类器的混淆矩阵。
因为大多数图片都在主对角线上,所以错误不明显,为了聚焦错误,将对角线全部填充为0,然后重新绘制。
可以发现第8列很亮,说明很多数字都被错误的判为8,这样我们就可以把精力放在改进数字8分类错误的问题上了。
3.6 多标签分类
比如人脸识别分类器在一张照片中识别出多张人脸,比如可以识别出张三、王五、赵四,那如果看到一张张三和李四的照片,就会输出 [1, 0, 1]
,即表示“是张三,不是王五,是赵四”,这就是多标签分类系统。
3.7 多输出分类
简单说就是多标签分类的泛化,其标签也可以是多类的。
比如一个去除图片噪声的系统,以刚刚手写数字举例,标签是28*28个,如果输入一张有噪音的图片,经过系统后,每个实例也是输出多个标签。
左边是噪声图片,右边是目标图片。
通过系统清理图片得到结果。