sklearn基础篇(二)-- 交叉验证评估模型性能

        训练机器学习模型的关键一步是要评估模型的泛化能力。如果我们训练好模型后,还是用训练集取评估模型的性能,这显然是不符合逻辑的。一个模型如果性能不好,要么是因为模型过于复杂导致过拟合(高方差),要么是模型过于简单导致导致欠拟合(高偏差)。可是用什么方法评价模型的性能呢?这就是这一节要解决的问题,你会学习到两种交叉验证计数,holdout交叉验证和k折交叉验证, 来评估模型的泛化能力。

1 留出法(holdout cross validation)

        评估模型泛化能力的典型方法是holdout交叉验证(holdout cross validation)。holdout方法很简单,我们只需要将原始数据集分割为训练集和测试集,前者用于训练模型,后者用于评估模型的性能。

        不过,在训练模型这一步,我们非常关心如何选择参数来提高模型的预测能力,而选择参数这一步被称为模型选择(model selection,注:不少资料将选择何种模型算法称为模型选择),参数选择是非常重要的,因为对于同一种机器学习算法,如果选择不同的参数(超参数),模型的性能会有很大差别。

         如果在模型选择的过程中,我们始终用测试集来评价模型性能,这实际上也将测试集变相地转为了训练集,这时候选择的最优模型很可能是过拟合的。

        更好的holdout方法是将原始训练集分为三部分:训练集、验证集和测试集。训练集用于训练不同的模型,验证集用于模型选择。而测试集由于在训练模型和模型选择这两步都没有用到,对于模型来说是未知数据,因此可以用于评估模型的泛化能力。下图展示了holdout方法的步骤:

sklearn基础篇(二)-- 交叉验证评估模型性能_第1张图片

        当然holdout方法也有明显的缺点,它对数据分割的方式很敏感,如果原始数据集分割不当,这包括训练集、验证集和测试集的样本数比例,以及分割后数据的分布情况是否和原始数据集分布情况相同等等。所以,不同的分割方式可能得到不同的最优模型参数。

优点:任务量小,缺点:太不精确,受数据随机性影响

        下一节,我们会学习到一种鲁棒性更好的模型评估方法,k折交叉沿则,即重复k次holdout方法提高鲁棒性。

代码实现:
        下面让我们载入 iris 数据集,并在此数据集上训练出线性支持向量机:

import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
from sklearn import svm

X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)    # 分割训练集和测试集

clf = svm.SVC(kernel='linear', C=1).fit(X_train, y_train)
clf.score(X_test, y_test)   # 0.9777777777777777

2 k折交叉验证(k-fold cross validation)

        k 折交叉验证通过对 k 个不同分组训练的结果进行平均来减少方差,因此模型的性能对数据的划分就不那么敏感。步骤如下:

  • 第一步,不重复抽样将原始数据随机分为 k 份;
  • 第二步,每一次挑选其中 1 份作为测试集,剩余 k-1 份作为训练集用于模型训练;
  • 第三步,重复第二步 k 次,这样每个子集都有一次机会作为测试集,其余机会作为训练集;
  • 第四步,在每个训练集上训练后得到一个模型,用这个模型在相应的测试集上测试,计算并保存模型的评估指标;
  • 第五步,计算 k 组测试结果的平均值作为模型精度的估计,并作为当前 k 折交叉验证下模型的性能指标。

        至于 k 折中的 k 到底设定为多少,这个又是一个调参的过程,当然了,这一步很少有人会调参,一般都是用5或10。但是如果你的数据集特别小,我们当然希望训练集大一点,这时候就要设定大一点的k值,因为 k 越大,训练集在整个原始训练集的占比就越多。但是呢,k 也不能太大,一则是导致训练模型个数过多,二则是k很大的情况下,各个训练集相差不多,导致高方差。要是你的数据集很大,那就把 k 设定的小一点咯,比如5。

        使用 k 折交叉验证来寻找最优参数要比holdout方法更稳定。一旦我们找到最优参数,要使用这组参数在原始数据集上训练模型作为最终的模型。k折交叉验证使用不重复采样,优点是每个样本只会在训练集或测试中出现一次,这样得到的模型评估结果有更低的方法。

        下图演示了10折交叉验证:
sklearn基础篇(二)-- 交叉验证评估模型性能_第2张图片

        其实呢,在将原始数据集划分为k部分的过程中,有很多不同的采样方法,比如针对非平衡数据的分层采样。分层采样就是在每一份子集中都保持原始数据集的类别比例。比如原始数据集正类:负类=3:1,这个比例也要保持在各个子集中才行。sklearn中实现了分层 k 折交叉验证。

这个方法充分利用了所有样本。但计算比较繁琐,需要训练 k 次,测试 k 次。

        下面的示例展示了如何通过分割数据,拟合模型和计算连续 5 次的分数(每次不同分割)来估计 linear kernel 支持向量机在 iris 数据集上的精度:

from sklearn.model_selection import cross_val_score
clf = svm.SVC(kernel='linear', C=1)
scores = cross_val_score(clf, X, y, cv=5)
print(scores)   # [0.96666667 1.         0.96666667 0.96666667 1.]     

        评分估计的平均得分和 95% 置信区间由此给出:

print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std()))        # Accuracy: 0.98 (+/- 0.02)

        下面看一下 K-fold 是怎样划分数据的:X 有四个数据,把它分成 2 折,结果中最后一个集合是测试集,前面的是训练集,每一行为 1 折:

import numpy as np
from sklearn.model_selection import KFold

X =["a", "b", "c", "d"]
kf = KFold(n_splits=2)
for train, test in kf.split(X):
    print("%s    %s" % (train, test))
    print(X[train], X[test])
    # [2 3]    [0 1]
    # [0 1]    [2 3]

        每一折由两个 arrays 组成,第一个作为 training set ,另一个作为 test set 。 由此,可以通过使用 numpy 的索引创建训练/测试集合。


3 留一法(LOOCV, Leave one out cross validation)

        当 k= n,即样本总数时,就叫做留一法,换言之每次只留下一个样本做测试集,其它样本做训练集,如果有 n 个样本,则需要训练 n 次,测试 n 次。这个方法用于训练的数据只比整体数据集少了一个样本,因此最接近原始样本的分布。但是训练复杂度增加了,因为模型的数量与原始数据样本数量相同。一般在数据缺乏时使用。例如下图,一共10个数据,就交叉验证十次

sklearn基础篇(二)-- 交叉验证评估模型性能_第3张图片

优点:

  • 适合小样本数据集
  • 利用所有的数据点,因此偏差将很低

缺点:

  • 重复交叉验证过程n次导致更高的执行时间
  • 测试模型有效性的变化大。因为针对一个数据点进行测试,模型的估计值受到数据点的很大影响。如果数据点被证明是一个离群值,它可能导致更大的变化

        LOOCC是保留一个数据点,同样的你也可以保留P个数据点作为验证集,这种方法叫LPOCV(Leave P Out Cross Validation)

同样的数据 X,我们看 LeaveOneOut 后是什么样子,那就是把它分成 4 折,结果中最后一个集合是测试集,只有一个元素,前面的是训练集,每一行为 1 折:

>>> from sklearn.model_selection import LeaveOneOut

>>> X = [1, 2, 3, 4]
>>> loo = LeaveOneOut()
>>> for train, test in loo.split(X):
...     print("%s  %s" % (train, test))
[1 2 3] [0]
[0 2 3] [1]
[0 1 3] [2]
[0 1 2] [3]


4 自助采样法(Bootstrapping)

        通过自助采样法,即在含有 n 个样本的数据集中,每次随机挑选一个样本,再放回到数据集中,再随机挑选一个样本,这样有放回地进行抽样 n 次,组成了新的数据集作为训练集。

        这里会有重复多次的样本,也会有一次都没有出现的样本,原数据集中大概有 36.8% 的样本不会出现在新组数据集中。

优点是训练集的样本总数和原数据集一样都是 n,并且仍有约 1/3 的数据不被训练而可以作为测试集。缺点是这样产生的训练集的数据分布和原数据集的不一样了,会引入估计偏差。此种方法不是很常用,除非数据量真的很少。


5 随机二次抽样(Random Subsampling)

        相当于k次Holdout取平均:每次取不一样的验证集(剩下的作为训练集),执行一遍获得指标,最后k次取平均。

参数:训练集、验证集的数据条目数,次数k

应用:在模型之间差异明显,或其他对于结果要求不高的领域,此法比较便捷。

优点:任务量小,缺点:太不精确


6 小结

        疑问:对于交叉验证法,如5折交叉验证,那么将会生成5个模型,到底应该选择哪个模型作为最终的模型呢?

        解答:通过阅读博文,发现交叉验证法是用来评估模型性能的,并不参与最后预测模型的生成。

        一、交叉验证法是用于小数据集的。大数据集可直接使用train-validation-test。
在研究对比不同算法的泛化性能时,使用测试集来评估,而把训练数据划分为训练集和验证集,基于验证集上的性能来进行模型选择和调参。

        使用train-validation-test的过程:

  • 将数据集划分为training set,validation set,testing set;
  • 对不同的3个算法svm,random forest,logistic regression,分别执行以下三步,得到其最优模型。
    • 对于一个算法,如svm,针对不同的核参数,在training set上训练模型;
    • 在validation set上评估不同核参数对应模型的结果,选择出最优的核参数;
    • 对该最优核参数,重新使用training set+validation set进行训练,得到最终的模型;
  • 在testing set上对这三个不同算法的性能进行评估,用来估计模型在实际使用时的泛化能力。

        二、交叉验证法是用于选择超参数的。如svm中核函数的参数选择,tuning parameter时,使用交叉验证法的平均评估结果来验证哪个参数最好。

        机器学习训练时主要需要学两样东西。

        一样是模型weights,比如coefficients and biases.

        另外一样是模型的超参数,比如学习率,regularisation strength什么的。

        cross validation 主要是为了找到最好的超参数。然后用最好的超参数训练模型,得到最终的模型weights。

        使用交叉验证进行tuning parameter的过程总结:

  1. 将全部数据集划分为training set和 testing set;
  2. 对不同算法,进行tuning parameter:
    • 对不同超参数,使用training set,进行5折交叉验证,得到评估结果;
    • 选择评估结果最好的那个超参数作为最优超参数;
    • 对最优超参数,重新使用training set训练模型;
  3. 使用testing set评估不同算法的泛化能力。
sklearn基础篇(二)-- 交叉验证评估模型性能_第4张图片

        补充,对于分层验证、重复交叉验证( k-fold cross validation with repetition)、对抗验证(Adversarial Validation)、时间序列的交叉验证(Cross Validation for time series)的介绍,请阅读:https://blog.csdn.net/WHYbeHERE/article/details/108192957


参考

  • Cross-validation: evaluating estimator performance:https://scikit-learn.org/stable/modules/cross_validation.html
  • K折交叉验证评估模型性能:https://ljalphabeta.gitbooks.io/python-/content/kfold.html
  • 交叉验证方法汇总:https://blog.csdn.net/WHYbeHERE/article/details/108192957
  • 为什么要用交叉验证:https://blog.csdn.net/aliceyangxi1987/article/details/73532651

你可能感兴趣的:(Machine,Learning,学习框架,机器学习,人工智能,交叉验证,留出法,留一法)