sklearn的交叉验证是机器学习中重要的一步,主要用来评估模型的误差,但是其中理解起来还是有点困难,尤其是cv的设置,如果过大就会报错。
网上有关于交叉验证的基础知识点,我就不介绍了,我主要从实践中说下关于交叉验证在分类器中应用的一些坑和难以理解的地方。
首先是交叉验证会不会改变模型参数?
不会。交叉验证是在model.fit()之后进行的一步,模型在fit的时候,就已经更新了参数,交叉验证只是为了在数据集上评估模型好坏用的,通过交叉验证来计算AUC,f1,precision,recall等指标。
交叉验证包括 cross_val_predict,cross_val_score,cross_val。
其中predict是输出预测值,score是可选的,可以选择一些指标去展示分数。
对于回归来说,可以选择score,但是对于分类器,还是需要使用predict。
例如:
Y_forest_pred = cross_val_predict(forest_clf, X_train, y_train_binary, cv = 10)
# Y_forest_pred.shape=(49, )
cv是可选的参数,cv也是最难理解的地方。
cv表示k折交叉,默认是cv=5(假如不设置cv参数)。
注意:如果estimators(估算器模型)是分类器,并且y是二类或多类,那么cv使用的是StratifiedKFold,如果不是分类器,那么就是KFold。
StratifiedKFold使用的是分层采样,这点需要注意。
思考一个问题:
假如我有62个数据,做sgd分类器,结局指标是True和False。先按照8:2的比例划分测试集和验证集,那么将会随机分为49和13例(python的sklearn会按舍去小数划分)。让我们集中注意力到49例的测试集:假如我训练好了sgd分类器, 随后进行交叉验证,那么请问,cv最大能设置为多少?
答案是min(sum(True)| sum(False)),意思就是在49例测试集的Y中,有多少True,有多少False,取两者中最小值,就是cv能设置的最大值。
解释下为什么会这样:首先sgd分类器是分类的,且Y值是True或者False的分布,因此如果调用cross_val_predict,那么就会使用StratifiedKFold这种分层K折验证法进行交叉验证。既然是分层,那么每次交叉验证划分测试集和验证集时,Y包含的True或False不能为零,至少是1。
回到刚才的例子,在49例测试集中,49例 X 应该对应着49例 Y (label),假如这次随机抽取的49个实例中,Y有18个True和31个False,那么cv最大只能是18。
为了更好的理解上述这段话,我们用倒推法:
假如我们设置了cv=18,它的意思就是说“把49个实例的测试集随机分为18份”,那么每一份里面就会有一个True(假设Y一共18个True)。当cv=19时,把49分成19份,因为一共只有18个True,所以就会导致有一份里没有True这个类别,这样cross_val_predict就会报错,说
ValueError: Cannot have number of splits n_splits=100 greater than the
number of samples: n_samples=49.
或者说
UserWarning: The least populated class in y has only 18 members, which
is less than n_splits=20.
从报错中很明显的看出来,就是n_split超出范围,修改正确后就可以使用。
怎么使用留一法?
留一法专门有一个函数,叫 leave one out。
from sklearn.model_selection import LeaveOneOut
调用代码如下:
from sklearn.model_selection import LeaveOneOut
loo = LeaveOneOut()
Y_sgd_pred = cross_val_predict(sgd_clf, X_train, Y_train_binary, cv = loo) #留一法