分类问题(二)分类器的性能衡量
性能衡量
评估一个分类器的性能一般比评估一个回归器(regressor)更为复杂,所以我们会在这里大篇幅介绍分类器的性能评估,并且它也有多种评估方法。
使用CV衡量准确度
一个比较好的评估模型的办法是使用交叉验证。sk-learn提供了一个交叉验证精准度的方法cross_val_score(),不过有时候若是需要实现一些自定义的目标,也可以实现一个交叉验证的方法。例如:
from sklearn.model_selection import StratifiedKFold from sklearn.base import clone skfolds = StratifiedKFold(n_splits=3, random_state=42) for train_index, test_index in skfolds.split(X_train, y_train_5): clone_clf = clone(sgd_clf) X_train_folds = X_train[train_index] y_train_folds = y_train_5[train_index] X_test_fold = X_train[test_index] y_test_fold = y_train[test_index]
clone_clf.fit(X_train_folds, y_train_folds) y_pred = clone_clf.predict(X_test_fold) n_correct = sum(y_pred == y_test_fold) print(n_correct / len(y_pred)) >0.09925 0.09675 0.10035
这个代码实现了 corss_val_score() 同样的功能。StratifiedKFold类会做分层采样,生成多个“折”。在每轮的迭代中,首先创建之前分类器的克隆,然后在每个“折”训练集上训练这个分类器,并在“折”测试集上进行预测,并最后计算预测的正确率。
然后我们试试直接用cross_val_score() 方法评估之前训练好的 SGDClassifier模型,使用的也是K-折交叉验证,指定3折。再次提醒一下大家,K-折交叉验证是指:将训练集分割为K个折(这里是3折),然后在每个“折”的数据上进行预测以及评估,使用非此“折”的训练数据进行训练。在这个例子中,训练集是60000,分成3折是每折20000。所以训练数据是40000,每次均在20000条验证集上做评估。
from sklearn.model_selection import cross_val_score cross_val_score(sgd_clf, X_train, y_train_5, cv=3, scoring='accuracy') >array([0.95035, 0.96035, 0.9604 ])
从验证集的评估来看,准确率达到了95% 以上,是一个非常高的准确率。这个结果看起来非常好,但是为什么说是“看起来非常好呢”?下面我们试试另一个非常蠢的分类器,这个分类器对每副图片仅输出“这个图片不是数字5”:
from sklearn.base import BaseEstimator
class Never5Classifier(BaseEstimator): def fit(self, X, y=None): pass def predict(self, X): return np.zeros((len(X), 1), dtype=bool)
大家可以猜测一下,这个模型的准确率是多少:
never_5_clf = Never5Classifier() cross_val_score(never_5_clf, X_train, y_train_5, cv=3, scoring='accuracy') >array([0.91125, 0.90855, 0.90915])
准确率高达90%以上!为什么会这样呢?
这是因为在所有图片中,仅有10%的图片是数字5。所以如果只是猜测图片不是数字5,都有高达90%以上的正确率。
以上这个例子说明了:为什么准确率对于分类器来说,一般不是一个好的性能评估方案,特别是在处理倾斜数据集(skewed datasets,也就是说有些类别的占比远大于其他类别)时。
接下来我们会介绍其他几种更好的衡量分类器的方法。