Я обнаружил своеобразный эффект, что RMSE становится меньше для тестового набора, чем для обучающего набора с функцией sample
с пакетом caret
.
Мой код выполняет общее разделение набора обучения и тестирования:
set.seed(seed)
training.index <- createDataPartition(dataset[[target_label]], p = 0.8, list = FALSE)
training.set <- dataset[training.index, ]
testing.set <- dataset[-training.index, ]
Это, например, дает RMSE для набора тестирования 0.651
, который выше, чем обучающий набор RMSE 0.575
- какожидается.
В соответствии с рекомендациями многих источников, например здесь , данные должны быть перетасованы, поэтому я делаю это до разделения выше:
# shuffle data - short version:
set.seed(17)
dataset <- data %>% nrow %>% sample %>% data[.,]
После этогов случайном порядке набор тестирования RMSE становится ниже 0.528
, чем обучающий набор RMSE 0.575
!Этот вывод согласуется с рядом алгоритмов, включая lm, glm, knn, kknn, rf, gbm, svmLinear, svmRadial
и т. Д.
Насколько мне известно, по умолчанию sample () имеет значение replace = FALSE
, поэтому не может быть никакой утечки данных в набор для тестирования.Такое же наблюдение имеет место в классификации (для точности и каппа), хотя createDataPartition
выполняет стратификацию, поэтому любой дисбаланс данных следует обрабатывать.
Я не использую какую-либо необычную конфигурацию, просто обычную перекрестную проверку:
training.configuration <- trainControl(
method = "repeatedcv", number = 10
, repeats = CV.REPEATS
, savePredictions = "final",
# , returnResamp = "all"
)
Что я здесь упустил?
-
Обновление 1. Подсказка об утечке данных в набор для тестирования
Я проверил распределение данных иобнаружил потенциальную подсказку для описанного эффекта.
Распределение обучающего набора:
. Freq prop
1 1 124 13.581599
2 2 581 63.636364
3 3 194 21.248631
4 4 14 1.533406
Распределение испытательного набора без shuffle:
. Freq prop
1 1 42 18.502203
2 2 134 59.030837
3 3 45 19.823789
4 4 6 2.643172
ПроверкаРаспределение набора с shuffle:
. Freq prop
1 1 37 16.299559
2 2 139 61.233480
3 3 45 19.823789
4 4 6 2.643172
Если мы посмотрим на режим (наиболее частое значение), его доля в тестовом наборе с shuffle 61.2%
ближе к пропорции обучающего набора63.6%
чем без перемешивания 59.0%
.
Я не знаю, как статистически интерпретировать это с помощью лежащей в основе теории - кто-нибудь может?
Моя интуиция заключается в том, что перетасовка делает стратификацию распределения тестового набора (неявно выполняемую createDataPartition()
) «более стратифицированный» - под этим я подразумеваю «ближе к распределению учебных наборов».Это может вызвать эффект утечки данных в противоположном направлении - в набор для тестирования.
Обновление 2: Воспроизводимый код
library(caret)
library(tidyverse)
library(magrittr)
data(BostonHousing)
seed <- 171
# shuffled <- TRUE
shuffled <- FALSE
if (shuffled) {
dataset <- BostonHousing %>% nrow %>% sample %>% BostonHousing[., ]
} else {
dataset <- BostonHousing %>% as_tibble()
}
target_label <- "medv"
features_labels <- dataset %>% select_if(is.numeric) %>%
select(-target_label) %>% names %T>% print
# define ml algorithms to train
algorithm_list <- c(
"lm"
, "glmnet"
, "knn"
, "gbm"
, "rf"
)
# repeated cv
training_configuration <- trainControl(
method = "repeatedcv", number = 10
, repeats = 10
, savePredictions = "final",
# , returnResamp = "all"
)
# preprocess by standardization within each k-fold
preprocess_configuration = c("center", "scale")
# select variables
dataset %<>% select(target_label, features_labels) %>% na.omit
# dataset subsetting for tibble: [[
set.seed(seed)
training.index <- createDataPartition(dataset[[target_label]], p = 0.8, list = FALSE)
training.set <- dataset[training.index, ]
testing.set <- testing.set <- dataset[-training.index, ]
########################################
# 3.2: Select the target & features
########################################
target <- training.set[[target_label]]
features <- training.set %>% select(features_labels) %>% as.data.frame
########################################
# 3.3: Train the models
########################################
models.list <- list()
models.list <- algorithm_list %>%
map(function(algorithm_label) {
model <- train(
x = features,
y = target,
method = algorithm_label,
preProcess = preprocess_configuration,
trControl = training_configuration
)
return(model)
}
) %>%
setNames(algorithm_list)
Запуск этого кода для shuffled = FALSE
и shuffled = TRUE
вкл.testing.set
дает:
model RMSE.testing RMSE.testing.shuffled
1 gbm 3.436164 2.355525
2 glmnet 4.516441 3.785895
3 knn 3.175147 3.340218
4 lm 4.501077 3.843405
5 rf 3.366466 2.092024
Эффект воспроизводим!