scikit-learn 交叉验证,评估评估器的性能(一)
sklearn 中的交叉验证方法。
0. CV
一个预测函数从所有可用数据中训练获得相关参数,再去判断同一组数据的标签是没有意义的,尽管其能够得到较高的分数。用它来判断其未曾见过的数据其分数将会明显降低,即过度拟合。为了避免这种情况,一般的做法是从所有可用数据中分出一部分作为测试数据。下图为经典的在模型训练时的交叉验证过程。
239
在 scikit-learn 中有 train_test_split 函数可以方便的将数据集分为 train 和 test。以下以 iris 数据集为例,并用一个线性SVM分类器进行训练。
1 | import numpy as np |
接下来从整个数据集中分出40%的数据作为测试集用来测试我们的分类器。
1 | X_train,X_test,y_train,y_test = train_test_split(iris.data, \ |
当对分类器的参数进行不断调整优化时,此时对测试集的预测会越来越精准,但是也可能会发生过度拟合的问题。即测试集的模型信息会逐渐地“泄露”到训练集中。此时分类器遍不再有泛化能力。为了解决这个问题,便需要从所有可用数据集中分出另一部分作为验证集(validation set)。分类器从训练集获得参数,并在验证集上进行验证,不断调整优化。最后在测试集上评估分类器的性能。
但是,将所有可用数据分为三个部分将极大的减少训练集中的样本数量。其结果可能会依赖特定的(训练/验证)集合的划分。
而交叉验证(Cross-Validation,CV)则是该问题的一个解决方法。对所有可用数据首先还是会划分出一个测试集。剩下的训练集不会再划分出一部分作为验证集,而是将会使用一种叫做 K-fold CV 的方法进行划分。训练集将会被划分成k个相同大小的集合。对于每一个小集合都将进行如下处理:
- 用其余k-1个小集合训练出一个模型;
- 用该小集合来验证由此产生的模型;
k-fold 交叉验证的分数是整个循环的计算的平均值。尽管这个过程需要消耗大量的计算,但是却充分利用了有限的数据样本。
3108
1. Computing CV metrics
使用CV最简单的方法是在分类器和数据集上直接使用cross_val_score函数。
下面的例子将展示如何在 iris 数据集上评价一个线性SVM分类器的准确性。首先将数据集分组;其次训练模型;最后连续计算5次得分(每次分割不同)。
1 | from sklearn.model_selection import cross_val_score |
在每一次CV过程中,计算分数方法默认是使用分类器自带的score方法。该方法可以通过指定 scoring 参数改变。
1 | scores = cross_val_score(clf, iris.data, iris.target, cv=5, socring='f1_macro') |
在Iris数据集的情况下,样本在目标类之间是平衡的,因此准确性和F1-score几乎相等。
当参数cv的值是一个整形数字时,cross_val_score 将默认使用 kfold 策略。如果分类器是从 ClassifierMixin 中派生出来的那么将使用 StratifiedKFold 策略。当然也可使用其他的 CV 迭代器,如下所示。
1 | from sklearn.model_selection import ShuffleSplit |
另外也可使用自定义的方法来划分数据,如下所示。
1 | def custom_cv_2folds(X): |
对划分数据进行数据转换
如同从训练集获得的分类器需要在测试集进行测试一样。数据的预处理也同样需要从训练集获得并同样运用到测试集中。
1 | from sklearn import preprocessing |
Pipeline 可以非常容易的将这些操作合并到CV中。
1 | from sklearn.pipeline import make_pipeline |