交叉验证是在机器学习建立模型和验证模型参数时常用的办法。交叉验证,顾名思义,就是重复的使用数据,把得到的样本数据进行切分,组合为不同的训练集和测试集,用训练集来训练模型,用测试集来评估模型预测的好坏。在此基础上可以得到多组不同的训练集和测试集,某次训练集中的某样本在下次可能成为测试集中的样本,即所谓“交叉”。
那么什么时候才需要交叉验证呢?交叉验证用在数据不是很充足的时候。比如在我日常项目里面,对于普通适中问题,如果数据样本量小于一万条,我们就会采用交叉验证来训练优化选择模型。如果样本大于一万条的话,我们一般随机的把数据分成三份,一份为训练集(Training Set),一份为验证集(Validation Set),最后一份为测试集(Test Set)。用训练集来训练模型,用验证集来评估模型预测的好坏和选择模型及其对应的参数。把最终得到的模型再用于测试集,最终决定使用哪个模型以及对应参数。
一:常见的交叉验证方法
1,K-Folds cross-validator
K折交叉验证提供训练/测试索引来分割训练/测试集中的数据。将数据集分割为k个连续的折叠(默认情况下不进行洗牌)。然后,当k - 1剩余的折叠构成训练集时,每个折叠将被使用一次作为验证。
所谓K折就是将数据集通过K次分割,使得所有数据既在训练集出现过,又在测试集出现过,当然,每次分割中不会有重叠。相当于无放回抽样。
from sklearn.model_selection import KFold X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]]) y = np.array([1, 2, 3, 4]) kf = KFold(n_splits=2) for train_index, test_index in kf.split(X): ... print("TRAIN:", train_index, "TEST:", test_index) TRAIN: [2 3] TEST: [0 1] TRAIN: [0 1] TEST: [2 3]
每次划分时对数据进行均分,有没有可能会出现极端情况:数据集有5类,抽取出来的也正好是按照类别划分的5类,也就是说第一折全是0类,第二折全是1类,等等;这样的结果就会导致,模型训练时,没有学习到测试集中数据的特点,从而导致模型得分很低,为了消除这种情况,提供了其他交叉验证的方式
2,Stratified k-fold cross validation
分层交叉验证(Stratified k-fold cross validation):首先它属于交叉验证类型,分层的意思是说在每一折中都保持着原始数据中各个类别的比例关系,比如说:原始数据有3类,比例为1:2:1,采用3折分层交叉验证,那么划分的3折中,每一折中的数据类别保持着1:2:1的比例,这样的验证结果更加可信。类似无放回抽样
from sklearn.model_selection import KFold
X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
y = np.array([1, 2, 3, 4])
kf = KFold(n_splits=2)
for train_index, test_index in kf.split(X):
... print("TRAIN:", train_index, "TEST:", test_index)
TRAIN: [2 3] TEST: [0 1]
TRAIN: [0 1] TEST: [2 3]
3,Leave-one-out Cross-validation 留一法
留一法Leave-one-out Cross-validation:是一种特殊的交叉验证方式。顾名思义,如果样本容量为n,则k=n,进行n折交叉验证,每次留下一个样本进行验证。主要针对小样本数据。
注意:LeaveOneOut()等价于KFold(n_split =n)和LeavePOut(p=1),其中n是样本数量。
由于测试集数量较多(与样本数量相同),这种交叉验证方法可能非常消耗计算性能。对于大型数据集,应该选择KFold、ShuffleSplit或hierarchy fiedkfold。
from sklearn.model_selection import LeaveOneOut X = np.array([[1, 2], [3, 4],[5,6]) y = np.array([1, 2]) loo = LeaveOneOut() for train_index, test_index in loo.split(X): ... print("TRAIN:", train_index, "TEST:", test_index) TRAIN: [1 2] TEST: [0] TRAIN: [0 2] TEST: [1] TRAIN: [0 1] TEST: [2]
4,Shuffle-split cross-validation
控制更加灵活:可以控制划分迭代次数、每次划分时测试集和训练集的比例,随机分割并不保证所有折叠都是不同的(也就是说:可以存在既不在训练集也不再测试集的情况),类似有放回的抽样;
from sklearn.model_selection import ShuffleSplit X = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [3, 4], [5, 6]]) y = np.array([1, 2, 1, 2, 1, 2]) rs = ShuffleSplit(n_splits=5, train_size=0.5, test_size=.25, random_state=0) for train_index, test_index in rs.split(X): print("TRAIN:", train_index, "TEST:", test_index) TRAIN: [1 3 0] TEST: [5 2] TRAIN: [4 0 2] TEST: [1 3] TRAIN: [1 2 4] TEST: [3 5] TRAIN: [3 4 1] TEST: [5 2] TRAIN: [3 5 1] TEST: [2 4]
5,GroupKFold cross-validation
不重叠组的K-fold迭代器变体,相同的组不会出现在两个不同的折叠中(不同组的数量必须至少等于折叠的数量)。
数据是按照一定分组进行打乱的,即先分堆,然后把这些堆打乱,每个堆里的顺序还是固定不变的。
from sklearn.model_selection import GroupKFold X = [1, 2, 2.2, 2.4, 2.3, 4.55, 5.8, 8.8, 9, 10] y = ['a','a','b','b','c','c','c','d','d','d'] groups = [1,1,1,2,2,2,3,3,3,3] gkf = GroupKFold(n_splits=3) for train, test in gkf.split(X,y,groups=groups): ...: print (train, test) [0 1 2 3 4 5] [6 7 8 9] [0 1 2 6 7 8 9] [3 4 5] [3 4 5 6 7 8 9] [0 1 2]
二:使用交叉验证的最简单的方法是cross_val_score在估计器和数据集上调用 帮助函数。
1,cross_val_score
sklearn.model_selection.cross_val_score(estimator, X, y=None, groups=None, scoring=None, cv=None, n_jobs=1, verbose=0, fit_params=None, pre_dispatch='2*n_jobs')
estimator :评估器,
cv可以是int类型,也可以是(KFold(n_splits=3))这样的策略生成器,当cv参数为整数时,默认情况下cross_val_score使用 KFold或StratifiedKFold策略
默认情况下,每个CV迭代计算的分数是score 估计量的方法。score 默认是以 scoring=’f1_macro’进行评测的,可以通过使用评分参数(scoring)来改变它:
from sklearn.datasets import load_iris from sklearn.model_selection import KFold,cross_val_score from sklearn.linear_model import LogisticRegression iris = load_iris() lr = LogisticRegression() kf = KFold(n_splits=3,shuffle=False,random_state=0) scores = cross_val_score(lr,iris.data,iris.target,cv=kf) print("KFold cross validation scores:{}".format(scores))
除了分类的,还有针对回归和聚类的评分参数,如下:
2,除了cross_val_score,sklearn中还提供一个方法cross_val_predict,它的功能就是返回每条样本作为CV中的测试集时,对应的模型对于该样本的预测结果。这就要求使用的CV策略能保证每一条样本都有机会作为测试数据。
该函数与输入中的每个元素cross_val_predict具有类似的接口 cross_val_score,但返回,当该元素在测试集中时为该元素获得的预测。只有交叉验证策略才能将所有元素精确地分配给测试集一次(否则引发异常)。
然后可以使用这些预测来评估分类器:
from sklearn.model_selection import cross_val_predict clf = svm.SVC(kernel='linear', C=1) predicted = cross_val_predict(clf, iris.data, iris.target, cv=10) metrics.accuracy_score(iris.target, predicted) 0.966...
注意,该计算的结果可能与使用cross_val_score的结果略有不同,因为元素以不同的方式分组。