sample()进行的数据改组将RMSE在测试集中的值降低到比训练集更低的值

问题描述 投票:3回答:2

[我已经发现了一个奇特的效果,即与sample软件包和caret功能一起使用的训练集相比,测试集的RMSE更低。

我的代码对训练和测试集进行了常见划分:

  set.seed(seed)
  training.index <- createDataPartition(dataset[[target_label]], p = 0.8, list = FALSE)
  training.set <- dataset[training.index, ]
  testing.set <- dataset[-training.index, ]

例如给出测试集0.651的RMSE,它高于训练集RMSE 0.575-如预期。

遵循许多资料来源的建议,例如here,应将数据重新排序,因此我在进行上述拆分之前就已经这样做:

  # 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进行分层,但在分类(准确性和kappa)中也会出现相同的观察结果,因此应处理任何数据不平衡的情况。

我不使用任何特殊配置,仅使用普通的交叉验证:

  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

测试集分布

随机播放:
  . Freq      prop
1 1   42 18.502203
2 2  134 59.030837
3 3   45 19.823789
4 4    6  2.643172

测试集分布with

随机播放:
  . Freq      prop
1 1   37 16.299559
2 2  139 61.233480
3 3   45 19.823789
4 4    6  2.643172

[如果我们查看模式(最频繁的值),则它在带有随机61.2%的测试集中的比例要比不带有随机63.6%的训练集比例59.0%更近。

我不知道如何用基本理论从统计学上解释这一点-有人可以吗?

[我的直觉是,改组使测试集分布(由createDataPartition()隐式执行)的分层更加“分层”-我的意思是“更接近训练集分布”。这可能会导致数据向相反方向泄漏的影响-进入测试集。

更新2:可复制代码
library(caret)
library(tidyverse)
library(magrittr)
library(mlbench)

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)

更新:用于计算测试集性能的代码

observed <- testing.set[[target_label]]
models.list %>%
  predict(testing.set) %>%
  map_df(function(predicted) {
    sqrt(mean((observed - predicted)^2))
    }) %>%
  t %>% as_tibble(rownames = "model") %>%
  rename(RMSE.testing = V1) %>%
  arrange(RMSE.testing) %>%
  as.data.frame

shuffled = FALSE上同时为shuffled = TRUEtesting.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

效果可再现!

我已经发现了一个奇特的效果,即测试集的RMSE低于带有插入符号包的带有样本功能的训练集的RMSE。我的代码对训练和...

r machine-learning statistics prediction r-caret
2个回答
4
投票

之所以获得不同的测试RMSE,是因为您拥有不同的测试集。您正在整理数据,然后每次都使用相同的training.index,因此没有理由相信每次测试集都将相同。

在您的原始比较中,您需要将改组后的测试数据的RMSE与改组后的训练数据(而不是原始训练数据)的RMSE进行比较。


0
投票

我完全同意强尼·菲尔普斯(Jonny Phelps)的回答。根据您的代码和插入符号功能代码,对混洗后的数据使用createDataPartition时,没有理由怀疑任何类型的数据泄漏。因此,性能差异必须归因于不同的训练/测试拆分。

© www.soinside.com 2019 - 2024. All rights reserved.