如何制作一个函数来对线性模型进行 K 折交叉验证?

How can I make a function that does K-fold cross validation for linear models?

我正在尝试开发一个对任何线性回归模型进行 k 折交叉验证的函数。我能够开发下面的代码

K.CV.2<-function(numberOfFolds, inputData){
  index <- sample(1:numberOfFolds, nrow(inputData), replace = T)
  inputData$index <- index
  mse.all <- c()
  for (n in 1:numberOfFolds) {
    training.data <- inputData[inputData$index!=n,]
    testing.data <- inputData[inputData$index==n,]
    model.hold <- lm(earn~height+sex+race+ed, data = training.data)
    predictions <- predict(model.hold, newdata=testing.data)
    mse.hold <- mean((testing.data$earn-predictions)^2)
    mse.all <- c(mse.all,mse.hold)
  }
  return(mse.all)
}

K.CV.2(numberOfFolds, Inputdata)

我对这个功能不满意,因为我试图让它更通用。我想要 function(numberOfFolds, y, x, InputData)

我希望能够使用 c() 函数传递 y 变量的列以及我将在 x 中用作解释变量的所有其他列。

有人可以 help/guide 我在正确的方向吗?

我猜是这样的。一些注意事项:

  • 提供示例数据会更容易提供帮助。我已经为这个案例生成了一些虚假数据,但以后要记住一些事情。一般来说,我强烈建议您练习模拟数据来测试您的模型和假设。
  • 不要使用 T。它不是保留值。您可以在脚本中编写 T <- FALSE,结果可想而知。
  • 直接传入您要使用的xy会更容易。这就是我在这里所做的。然后,您可以遍历数据帧并传入子集 x 和您想要的任何 y,但它使 CV 函数更清晰。
  • 除非绝对必要,否则不要增加对象。参见 the R inferno book
  • 最好避免在代码中使用 1:n。如果 n 为零,它会创建向量 c(1, 0),这通常会导致意外结果。
npred <- 10
nobs <- 100
mat <- matrix(rnorm(npred * nobs), ncol = npred, nrow = nobs)
beta <- rnorm(npred, sd = 2)
y <- (mat %*% beta + rnorm(100, sd=0.2))[, 1]
x <- as.data.frame(mat)

cv_lm <- function(x, y, nfolds) {
  ## don't use T; it's dangerous.
  index <- sample(seq_len(nfolds), nrow(x), replace = TRUE)
  stopifnot(nrow(x) == length(y)) ## check to make sure the input is valid

  ## declare output as a vector of length nfolds
  mse <- numeric(nfolds)
  ## use seq_len(nfolds) instead of 1:nfolds
  for (n in seq_len(nfolds)) {
    ## create x and y training/test split
    x_training <- x[index != n, ]
    x_testing <- x[index == n, ]
    y_training <- y[index != n]
    y_testing <- y[index == n]
    ## fit model (y ~ . means "y against everything")
    fit <- lm(y_training ~ ., data = x_training)
    predictions <- predict(fit, newdata = x_testing)
    ## don't grow vectors
    mse[[n]] <- mean((y_testing-predictions)^2)
  }
  return(mse)
}

## predict y with x (true predictors)
cv_lm(x = x, y = y, nfolds = 10)
#>  [1] 0.07503477 0.02913210 0.03467926 0.03762000 0.03291574 0.05687162
#>  [7] 0.01023195 0.06304727 0.02435436 0.06634923
## predict first predictor in x with the other 9 (no true relationship, hence larger MSE)
cv_lm(x = x[, 2:10], y = x[, 1], nfolds = 10)
#>  [1] 0.7447689 1.4850093 1.0964575 2.5117445 1.1037217 1.0684408 1.7798122
#>  [8] 0.9962255 1.0208430 1.3867716