如何使用交叉验证来确定使用训练、验证和测试集的最终模型

Posted

技术标签:

【中文标题】如何使用交叉验证来确定使用训练、验证和测试集的最终模型【英文标题】:How to use Cross Validation to Determine a Final Model using Training, Validation, & Test Sets 【发布时间】:2020-11-18 16:07:43 【问题描述】:

我无法理解模型选择阶段和最终模型测试阶段需要使用哪些数据集:训练、验证和测试。我尝试在下面详细解释它,同时在底部发布可重现的代码。感谢您的所有意见/建议!

假设我们使用 Kaggle 上可用的开放 "Life Expectancy (WHO)" 数据集来创建对特征 Life expectancy 的预测,同时使用 RMSE 作为我们的误差度量。 (我在这里更多地询问 CV 背后的概念,而不是针对最低 RMSE)。 我们首先从原始数据集 led 中划分训练和测试集 led_trainled_test

接下来,我们创建一个线性模型,其中 y = Life expectancy 和 x = GDP,数据 = led_train,并使用 Caret 包使用重复交叉验证对随机森林和 knn 模型执行相同的操作。然后我们使用新创建的模型和led_test 运行预测。 RMSE 可以使用真实评分与预测评分的函数来计算。

我现在在测试集上有线性模型的 RMSE = 9.81141、随机森林 = 9.828415、kNN = 8.923281。基于这些值,我显然会选择 kNN 模型作为我的“最终模型”,但是我不确定如何在新的“未见”数据上对其进行测试以了解它的实际性能。

我是否需要将“led”分成 3 组(训练、验证和测试),然后在模型选择阶段使用验证,为“最终模型”保存测试?此外,如果我选择 kNN 模型,我是否会将 train 函数 = led_train 中的数据更改为 led 以便在所有数据上运行,然后使用 led_test 进行预测?在最终模型中,我会再次设置 trControl 并运行交叉验证,还是不再需要,因为这是在训练数据上完成的?请在下面找到我发布的可重现代码(您必须根据您的 wd 在 .csv 中阅读)并再次感谢您查看!

*为了重现性,种子设置为 123,我正在运行 R 3.63。

library(pacman)
pacman::p_load(readr, caret, tidyverse, dplyr)

# Download the dataset:
download.file("https://raw.githubusercontent.com/christianmckinnon/StackQ/master/LifeExpectancyData.csv", "LifeExpectancyData.csv")

# Read in the data:
led <-read_csv("LifeExpectancyData.csv")

# Check for NAs
sum(is.na(led))
# Set all NAs to 0
led[is.na(led)] <- 0

# Rename `Life expectancy` to life_exp to avoid using spaces
led <-led %>% rename(life_exp = `Life expectancy`)

# Partition training and test sets
set.seed(123, sample.kind = "Rounding")
test_index <- createDataPartition(y = led$life_exp, times = 1, p = 0.2, list = F)
led_train <- led[-test_index,]
led_test <- led[test_index,]

# Add RMSE as unit of error measurement
RMSE <-function(true_ratings, predicted_ratings)
  sqrt(mean((true_ratings - predicted_ratings)^2))


# Create a linear model
led_lm <- lm(life_exp ~ GDP, data = led_train)
# Create prediction
lm_preds <-predict(led_lm, led_test)
# Check RMSE
RMSE(led_test$life_exp, lm_preds)
# The linear Model achieves an RMSE of 9.81141

# Create a Random Forest Model with Repeated Cross Validation
led_cv <- trainControl(method = "repeatedcv", number = 5, repeats = 3,
                      search = "random")
# Set the seed for reproducibility:
set.seed(123, sample.kind = "Rounding")
train_rf <- train(life_exp ~ GDP, data = led_train,
                  method = "rf", ntree = 150, trControl = led_cv,
                  tuneLength = 5, nSamp = 1000, 
                  preProcess = c("center","scale"))
# Create Prediction
rf_preds <-predict(train_rf, led_test)
# Check RMSE
RMSE(led_test$life_exp, rf_preds)
# The rf Model achieves an RMSE of 9.828415

# kNN Model:
knn_cv <-trainControl(method = "repeatedcv", repeats = 1)
# Set the seed for reproducibility:
set.seed(123, sample.kind = "Rounding")
train_knn <- train(life_exp ~ GDP, method = "knn", data = led_train,
                   tuneLength = 10, trControl = knn_cv,
                   preProcess = c("center","scale"))
# Create the Prediction:
knn_preds <-predict(train_knn, led_test)
# Check the RMSE:
RMSE(led_test$life_exp, knn_preds)
# The kNN model achieves the lowest RMSE of 8.923281

【问题讨论】:

请看Order between using validation, training and test sets和Should Cross Validation Score be performed on original or split data? 这个例子是不可重现的,因为 led 没有定义 @RobertWilson 你是绝对正确的——谢谢你指出这一点。我已经编辑了要在 csv 中读取的代码,并希望它现在可以重现! 【参考方案1】:

我的方法如下。最终模型应使用所有数据。我不确定在最终模型中不包含所有数据的动机是什么。你只是在浪费预测能力。

对于交叉验证,只需将数据拆分为训练和测试数据。然后为完整模型选择性能最好的建模方法,然后创建完整模型。

当前代码的更大问题是交叉验证方法可能会导致两件事:虚假的准确性和潜在的虚假模型比较。您需要在交叉验证中处理时间自相关。例如,如果我的训练数据集具有英国 2014 年和 2016 年的特征,您期望像随机森林这样的东西能够高精度地预测 2015 年的预期寿命。这可能就是您使用当前类型的交叉验证所测量的全部内容。最好创建一个隔离的数据集,以便训练和测试的国家/地区不同,或者将其分成明显不同的时间段。确切的方法将取决于您希望模型准确预测的内容

【讨论】:

感谢您的方法@RobertWilson!当您说“最终模型应该使用所有数据”时,您的意思是我应该像这样拟合最终模型:train_knn &lt;- train(life_exp ~ GDP, method = "knn", data = led, tuneLength = 10, trControl = knn_cv, preProcess = c("center","scale")) 然后用knn_preds &lt;-predict(train_knn, led_test) 再次预测我担心led 已经包含相同的数据led_test 这将导致最终模型的 RMSE 明显低于选择阶段的前一个模型。 此外,您对这种 cv 方法的固有缺陷是完全正确的,尽管这个问题更关心在建模的不同阶段应该使用哪些集合:训练、验证或测试。跨度> 我猜这取决于您要使用该模型的内容,这在原始帖子中可能不清楚。我对此的看法是,最终模型上的 RSME 并不重要。重要的是训练/测试模型上的 RMSE。这可以让您了解模型的预测能力。当然,这可能很难解释。火车中的数据较少,因此会导致模型的预测能力较低。但话又说回来,如果您的 CV 方法不理想,您最终可能会高估预测能力。

以上是关于如何使用交叉验证来确定使用训练、验证和测试集的最终模型的主要内容,如果未能解决你的问题,请参考以下文章

R:训练数据集的 k 折交叉验证

机器学习系列(二十四)——交叉验证与偏方差权衡

使用交叉验证的 KNN 分类器

验证集与测试集有啥区别?为啥要分训练集、验证集和测试集?

如何在没有交叉验证的情况下运行网格搜索?

为啥要划分训练集、验证集和测试集