模型选择和交叉验证:正确的方法


34

CrossValidated中有许多关于模型选择和交叉验证的主题。这里有一些:

但是,这些线程的答案是相当通用的,并且大多突出了交叉验证和模型选择的特定方法的问题。

为了使事情尽可能具体,例如,假设我们正在使用带有RBF内核的SVM: ,并且我有一个特征X和标签y的数据集,我想K(x,x)=(γ|xx|)2

  1. 找到我的模型的最佳值(和çγC
  2. 用我的数据集训练SVM(用于最终部署)
  3. 估计泛化误差和该误差周围的不确定性(方差)

为此,我将亲自进行网格搜索,例如,尝试和每种可能组合 。为简单起见,我们可以假设以下范围:γCγ

  • C{10,100,1000}
  • γ{0.1,0.2,0.5,1.0}

更具体地说,使用我的完整数据集,我可以执行以下操作:

  1. 对于每对(,),我在我的数据集上进行倍交叉验证(例如)的重复迭代(例如100次随机重复),即我在倍上训练我的SVM 并评估左折上的错误,遍历所有折。总体而言,我收集了100 x 10 = 1000个测试错误。γ ķ ķ = 10 ķ - 1 ķCγKK=10K1K
  2. 对于每个这样的(,)对,我计算这1000个测试错误的均值和方差。γ μ 中号σ 中号CγμM,σM

现在,我想选择用于在完整数据集上训练最终SVM的最佳模型(最佳内核参数)。我的理解是,选择误差均值和方差为最低的模型是正确的选择,并且该模型的为是我对模型的泛化误差偏差和方差的最佳估计。完整的数据集。σ 中号μ 中号σ 中号μMσMμMσM

但是,在阅读了上面线程中的答案之后,我得到的印象是,这种用于选择最佳SVM进行部署和/或估计其错误(通用性能)的方法存在缺陷,并且有更好的选择方法。最佳SVM并报告其错误。如果是这样,它们是什么?我正在寻找一个具体的答案。

坚持这个问题,我该如何特别地选择最佳模型正确估计其泛化误差


为了使事情尽可能具体,请告诉我们:数据集中有多少个统计上独立的案例?您评估优化的目标函数是什么/您使用哪种错误度量?您实际上在参数网格上观察到所选误差度量的一致行为吗?如果您正在谈论分类并且您的误差度量允许这样做:由于有限的样本量,迭代的交叉验证结果如何与您期望(但无法度量)的方差进行比较?
cbeleites支持Monica

您可能会发现有趣的文章:optimtyprediction.com/files/pdf/V2A5.pdf
2013年

2
+1是非常清晰详细的问题,也是与整个数据科学界相关的问题。
NickBraunagel

Answers:


20

我在JMLR中的论文解决了这个确切的问题,并说明了问题中建议的过程(或至少一个非常类似的过程)为何导致乐观的性能估计结果:

加文·考利(Gavin C. Cawley),尼古拉·LC·塔尔伯特(Nicola LC Talbot),“关于模型选择中的过度拟合以及性能评估中的后续选择偏差”,《机器学习研究杂志》,第11期,(7月):2079−2107,(www。

要记住的关键是,交叉验证是一种用于估计生成模型的方法而不是模型本身的泛化性能的技术。因此,如果选择内核参数是生成模型的过程的一部分,那么您还需要对模型选择过程进行交叉验证,否则最终将获得乐观的性能估计(与您建议的过程一样)。

假设您有一个函数fit_model,该函数接收由属性X和所需的响应Y组成的数据集,并返回该数据集的拟合模型,包括超参数的调整(在本例中为内核和正则化参数)。可以通过许多方式执行超参数的调整,例如,最小化X和T上的交叉验证误差。

步骤1-使用fit_model函数将模型拟合为所有可用数据。这为您提供了将在操作中使用的模型。

第2步-绩效评估。使用所有可用数据执行重复的交叉验证。在每个折叠中,数据被分为训练集和测试集。使用训练集拟合模型(记录拟合模型的超参数值)并评估测试集的性能。使用所有测试集的平均值作为性能估计值(也许还可以查看值的分布)。

第3步-超参数设置的可变性-对第3步中收集的超参数值进行分析。但是,我应该指出,超参数没有什么特别之处,它们只是已估计的模型参数(间接)。为了计算/数学上的方便,它们被视为超参数而不是参数,但这不是必须的。

使用交叉验证的问题在于,训练数据和测试数据不是独立的样本(因为它们共享数据),这意味着性能估计值和超参数的方差估计可能有偏差(即小于每次折叠中真正独立的数据样本的数据)。如果在计算上可行,我可能会使用自举而不是重复交叉验证,然后打包结果模型。

关键是要获得公正的性能评估,无论您使用哪种方法生成最终模型(fit_model),都必须在交叉验证过程的每一步中独立完整地重复执行该过程。


这是一个很好的答案。当您说rather than repeated cross-validation you would go for bootstrapping-到底有什么区别?两者都涉及将数据分割成多次重复traintest,然后在训练train和评估test,不是吗?
乔什(Josh)

4
自举(带替换采样)似乎是执行大量重新采样的更自然的方法,因为它比重复进行交叉验证更为随机。对于自举,使用袋装套件是一个不错的功能,袋装误差作为性能评估。两者之间没有太多选择。
迪克兰有袋博物馆,2013年

谢谢@Dikran-这让我想知道,假设使用了自举法,考虑到重复的均值和方差,您如何选择一个好的模型?(即您将遵循哪种模型选择协议?)。这个问题恰好构成这个问题。在该线程上获取您的输入将非常有价值!
2013年

@DikranMarsupial您能否为第1-3步发布代码(例如Python或R)?在查看具体代码时,我发现更容易理解此类过程。
tobip 2014年

1
关键信息:“关键是要获得公正的性能评估,无论您使用哪种方法生成最终模型(fit_model),都必须在交叉验证过程的一步中独立完整地重复进行。” 这个确切的信息也在《统计学习的要素》(请参见第7.10.2节)中传达
NickBraunagel,

0

γC

优化这些超参数并使用它们训练SVM的过程也只是机器学习算法。不仅优化SVM的内部参数(支持向量),还优化了超参数。

现在您有两个问题[可以独立解决]:

阅读交叉验证滥用(报告性能以获得最佳超参数值),以确保您不会混淆它们。


针对您问题的具体问题的特定(可能不是最佳)解决方案:

k = 5
loss_CV = zeros(k)
for i in 1:k 
    Xi_train, Xi_test = folds(X,k)[i]
    loss = zeros((3,3))
    for lambda in {0.1,0.2,0.5,1.0}
        for C in {10,100,1000}
            for j in 1:k
                Xj_train, Xj_test = folds(Xi_train,k)[j]
                model = SVM(Xj_train,lambda, C)
                loss[lambda,C] += test_error(model,Xj_test)
    lambda, C = argmax(loss)
    model = SVM(Xi_train,lambda, C)
    loss_CV += test_error(model,Xi_test)

loss = zeros((3,3))
for lambda in {0.1,0.2,0.5,1.0}
    for C in {10,100,1000}
        for j in 1:k
            Xj_train, Xj_test = folds(Xi_train,k)[j]
            model = SVM(Xj_train,lambda, C)
            loss[lambda,C] += test_error(model,Xj_test)
lambda, C = argmax(loss)
model = SVM(Xi_train,lambda, C)

在这里,model将是您的“最佳模型”和loss_CV“对其泛化误差的正确估计”(尽管有偏差,但您不能吃蛋糕也不能吃)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.