嵌套交叉验证(Nested CV)

ad6bcbb63116e1246b252add9e3074b4.jpeg

最近,突然想要用R来搞搞机器学习,这让我想起了一个被尘封的草稿,当初让我放弃使用R做嵌套交叉验证的想法。于是,决定好好完善一番再发出去。有些事情不捋清楚,它就会在将来的某个时候等着你,让你心神不宁。先从交叉验证开始。

交叉验证

交叉验证(Cross Validation; CV)用于检验机器学习的模型表现,选择模型。如下图显示的便是一个3-fold CV。其中loop都使用了相同的随机森林(RF)模型。

e985cfb4e9e038e2b3b99c5c7c011d1d.png

(https://ploomber.io/blog/nested-cv/)

使用同样的方法,可以对比不同模型的表现,例如,如果支持向量机(SVM)比随机森林(RF)的表现好,便选用支持向量机作为最终模型。同样地,每个loop都使用相同的模型超参数)。

f7db00b769624ee4248bd39391ec87df.png

(https://ploomber.io/blog/nested-cv/)

机器学习的模型都会涉及超参数(hypoparameters),选择不同的超参数可能会让模型表现改变。因此做交叉验证也可以用于调参。

e2d55312048de1f97a26295039b66194.png

(https://ploomber.io/blog/nested-cv/)

例如,这里使用交叉验证的结果说明,支持向量机(SVM)选择线性(Linear)内核比非线性(i.e., Poly)内核表现更好。这样做潜在的问题是,一旦选择了表现最好的超参数,该模型的表现通常会被报告为最优模型。由于这里每一次交叉验证的循环中,都使用了相同的数据来调参,因此存在着严重的优化偏差(bias)问题,可能导致对模型表现的乐观估计。

嵌套交叉验证fb6194068ff054e0acfde9d3628be322.png

(https://ploomber.io/blog/nested-cv/)

如图所示,嵌套交叉验证进而将外层(outer)每个循环中的训练集再做一个k折交叉验证进行调参,这里调参的是n_estimations的数量,结果表示n_esimations=5的第三个fold的表现好,因此选择该参数的模型作为第三个fold的模型。实际中,可能会使用grid.search等策略对多种参数进行评估,每一个组合都会做一次k折交叉验证计算平均模型表现,最好的选为一个外层的最优模型。

重复交叉验证(Repeated CV)

由于在做k折交叉验证时,将数据一次划分为了k组,这样的划分存在随机性。有可能某一次划分会得到较好的结果,而另一次划分得到较差的结果。因此做重复交叉验证能减小由于将数据划分而造成的随机变化。

7c1e162529f6921908367a42da0714a1.jpeg

R中的交叉验证

实际看一下caret的文档,调参类似于Python中的GridSearchCV。

f17866ec36530280083d196edaadf5ef.png

(https://topepo.github.io/caret/model-training-and-tuning.html)

例如使用重复交叉验证对一个SVM调参ff413c6760de672e1f7893887be29455.jpeg输出如下:6bcf36701b636ef49fdf3869fdadb686.png

(https://stats.stackexchange.com/questions/421701/tuning-svm-parameters-in-r)

输出的时候出现了Resampling,指的是对数据进行重采样的方式。交叉验证也算作一种重采样的方式。在trainControl的method中还有除了交叉验证的其他选项,例如resampling。

2b9ce2c4a5dc2344e96af4957529524d.png(http://appliedpredictivemodeling.com/blog/2017/9/2/njdc83d01pzysvvlgik02t5qnaljnd)

想在R中做Nested CV?

在R常用的工具包Caret并未提供Nested CV的做法,工具包作者首先质疑了做Nested CV的收益,然后加了工单。

d33f6c758a01806a84ade65f4ab94ac4.png

随后又嫌麻烦,写了个相关的blog,要做嵌套的就照着做吧。

5a7cd0bdb405a21273a19b2ca1f01f2e.png

博客中,作者使用数据说明了做嵌套过程的收益其实不大。

5598366890a496ca0012ab5f00beaf8d.png

(http://appliedpredictivemodeling.com/blog/2017/9/2/njdc83d01pzysvvlgik02t5qnaljnd)

类似的观点:

b92662181ccc714ea26b683adebefd5b.png9554d33ed4f2cd2ade131345076b1daa.jpeg

所以大部分时候,使用标准版的CV调参可以提高运行速度,对于200个参数组合,10-fold标准版CV计算量是2000,而10-fold嵌套CV的计算量则是20000。但是当参数数量>>样本量时就需要考虑嵌套交叉验证,Python很方便,在R中有以下几种思路:

  1. 在R中使用reticulate包调用Python代码。如果知道Python的嵌套怎么做,难度1星。

  2. 使用R工具包nestedcv,难度2星。

3. 手动增加外层循环或者参照caret作者的博客,难度4星。

aa5543b5768fff0962fbadbe4b94e09d.jpeg

(https://stats.stackexchange.com/questions/125843/outer-crossvalidation-cycle-in-caret-package-r)

df2e1185021e49a5c7d6478b34a45e23.png

嵌套交叉验证是一种模型选择和评估的方法,它将数据集分为内部训练集、内部测试集、外部训练集和外部测试集四部分。其中,内部训练集用于调整模型的超参数,内部测试集用于评估超参数的性能,外部训练集用于训练最终的模型,外部测试集用于评估最终模型的性能。因此,嵌套交叉验证可以更准确地评估模型的性能和选择最优的超参数。 下面是一个使用嵌套交叉验证进行超参数搜索的基础代码: ```python from sklearn.datasets import load_iris from sklearn.model_selection import GridSearchCV, cross_val_score from sklearn.tree import DecisionTreeClassifier iris = load_iris() X, y = iris.data, iris.target # 定义决策树分类器 dtc = DecisionTreeClassifier() # 定义超参数搜索空间 param_grid = {'max_depth': [1, 2, 3, 4, 5], 'min_samples_split': [2, 3, 4]} # 内部交叉验证 grid_search = GridSearchCV(dtc, param_grid=param_grid, cv=5) grid_search.fit(X, y) # 记录最佳超参数 best_params = grid_search.best_params_ # 外部交叉验证 dtc = DecisionTreeClassifier(**best_params) scores = cross_val_score(dtc, X, y, cv=3) print('Best params:', best_params) print('CV scores:', scores) print('Mean CV score:', scores.mean()) ``` 上述代码中,我们使用了决策树分类器作为模型,定义了超参数搜索空间,然后使用GridSearchCV进行内部交叉验证,找到最佳超参数。接着,我们使用最佳超参数训练最终的模型,并使用cross_val_score进行外部交叉验证,评估最终模型的性能。 我们可以通过修改内部、外部cv折数来观察、记录和分析实验结果。一般来说,内部cv折数越大,模型调优的准确性越高,但计算成本也越高;外部cv折数越大,最终模型评估的准确性越高,但计算成本也越高。因此,需要在时间和准确性之间进行权衡。 总之,嵌套交叉验证是一种重要的模型选择和评估方法,可以更准确地评估模型的性能和选择最优的超参数。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值