R 中用于线性模型的 K 折交叉验证的通用函数

Generic Function for K-Fold Cross-Validation In R for Linear Models

大家好,我需要帮助来解决下面的问题。我用的是R语言。

我使用的数据集叫做 wages,它来自一个叫做 library(ISLR) 的包 数据(工资).

无论如何,我正在尝试开发一个允许我对任何一般线性模型执行 k 折交叉验证的函数。

我正在使用的函数的 inputs/arguments 是 function(numberOfFolds, y,x,InputData)

y 是因变量 x 是数据集中的所有其他变量 inputdata是工资的数据集 numberOfFolds 基本上是 k.

我开发了以下代码,但得到的是 NaN 值。不知道出了什么问题!有人可以帮忙吗

my.k.fold.1<- function(numberOfFolds, y,x,inputData){
  index<-sample(1:numberOfFolds, nrow(inputData), replace = T)
  inputData$index<-index
  
  mse<-vector('numeric', length = numberOfFolds)
  for (n in 1:numberOfFolds) {
    data.train<-inputData[index!=n,]
    data.test<-inputData[index==n,]
    my.equation<-paste(y,paste(x, collapse = '+'),sep='~')
    formula.1<-formula(my.equation)
    model.test<-lm(formula.1, data = data.train)
    predictions<-predict(model.test, newdata=data.test)
    mse[[n]]<-mean((data.test$y-predictions)^2)
  }
  return(mse)
}

my.k.fold.1(numberOfFolds = 5, y='earn', x=c('race', 'sex', 'ed', 'height', 'age'), inputData = wages)

我想保持参数不变,我可以写下 y 和 xs 中的列名

这是因为y变量是字符串,所以data.test$y等价于data.test[["y"]]。您应该将其替换为 data.test[[y]],这相当于 data.test$earn if y="earn":

my.k.fold.1<- function(numberOfFolds, y,x,inputData){
  index<-sample(1:numberOfFolds, nrow(inputData), replace = T)
  inputData$index<-index
  
  mse<-vector('numeric', length = numberOfFolds)
  for (n in 1:numberOfFolds) {
    data.train<-inputData[index!=n,]
    data.test<-inputData[index==n,]
    my.equation<-paste(y,paste(x, collapse = '+'),sep='~')
    formula.1<-formula(my.equation)
    model.test<-lm(formula.1, data = data.train)
    predictions<-predict(model.test, newdata=data.test)
    mse[[n]]<-mean((data.test[[y]]-predictions)^2)
  }
  return(mse)
}

这是一个通用函数。参数名称是自我描述的。我添加了一个参数 verbose,默认为 FALSE.
下面使用内置数据集 mtcars.

进行测试
my.k.fold.1 <- function(numberOfFolds, inputData, response, regressors, verbose = FALSE){
  fmla <- paste(regressors, collapse = "+")
  fmla <- paste(response, fmla, sep = "~")
  fmla <- as.formula(fmla)
  index <- sample(numberOfFolds, nrow(inputData), replace = TRUE)
  mse.all <- numeric(numberOfFolds)
  for (n in seq_len(numberOfFolds)) {
    inx <- which(index != n)
    data.training <- inputData[inx, ]
    data.test <- inputData[-inx, ]
    if(verbose){
      msg <- paste("fold:", n, "nrow(training):", nrow(data.training), "nrow(test):", nrow(data.test))
      message(msg)
    }
    model <- lm(fmla, data = data.training)
    predicted <- predict(model, newdata = data.test)
    mse <- mean((data.test[[response]] - predicted)^2)
    mse.all[n] <- mse
  }
  return(mse.all)
}

X <- names(mtcars)[-c(1, 3, 5, 7)]
y <- "mpg"

set.seed(2021)
mse.kcv <- my.k.fold.1(5, mtcars, response = y, regressors = X, verbose = TRUE)
mse.kcv
#[1] 14.255583  8.355831  2.765447  7.539299 10.151655