与R中的glmnet和LOOCV有关的次要问题

时间:2019-07-13 22:04:46

标签: r machine-learning regression linear-regression cross-validation

我尝试使用cv.glmnet和glmnet留出交叉验证拆分来拟合正则化模型(LASSO,Ridge,ElasticNet)。

我使用了这个DATASET,数据集有517行和13列(其中两个是分类变量)。因变量是“区域”。

我想建立一个没有分类变量的模型。然后是计算每个LOOCV运行的系数平均值,以及R平方和Root均方的平均值。

数据集的最后10行如下

tail(wdbc,10)
    X Y month day FFMC   DMC    DC  ISI temp RH wind rain  area
508 2 4   aug fri 91.0 166.9 752.6  7.1 25.9 41  3.6  0.0  0.00
509 1 2   aug fri 91.0 166.9 752.6  7.1 25.9 41  3.6  0.0  0.00
510 5 4   aug fri 91.0 166.9 752.6  7.1 21.1 71  7.6  1.4  2.17
511 6 5   aug fri 91.0 166.9 752.6  7.1 18.2 62  5.4  0.0  0.43
512 8 6   aug sun 81.6  56.7 665.6  1.9 27.8 35  2.7  0.0  0.00
513 4 3   aug sun 81.6  56.7 665.6  1.9 27.8 32  2.7  0.0  6.44
514 2 4   aug sun 81.6  56.7 665.6  1.9 21.9 71  5.8  0.0 54.29
515 7 4   aug sun 81.6  56.7 665.6  1.9 21.2 70  6.7  0.0 11.16
516 1 4   aug sat 94.4 146.0 614.7 11.3 25.6 42  4.0  0.0  0.00
517 6 3   nov tue 79.5   3.0 106.7  1.1 11.8 31  4.5  0.0  0.00

我的尝试代码如下

set.seed(123) 
  data <- read.csv("https://archive.ics.uci.edu/ml/machine-learning-databases/forest-fires/forestfires.csv") 
  data<-data[-(3:4)] 
  nrFolds <- 517
  folds <- rep_len(1:nrFolds, nrow(data))
  for(k in 1:nrFolds) {
      fold <- which(folds == k)
      data.train <- data[-fold,]
      data.test <- data[fold,]
      x.train <- as.matrix(data.train[-11])
      y.train <- as.matrix(data.train[11])
      x.test <- as.matrix(data.test[-11])
      y.test <- as.matrix(data.test[11])
      cv <- cv.glmnet(x.train, y.train, alpha = 0)
      # cv$lambda.min
      model <- glmnet(x.train, y.train, alpha = 0, lambda = cv$lambda.min)
      coef(model) 
      predictions <- model %>% predict(x.test) %>% as.vector()
      RMSE <- RMSE(predictions, data.test$area)
      Rsquare <- R2(predictions, data.test$area)
      LL <- list(cv,model,coef(model),predictions, RMSE,Rsquare)
  }
  LL

代码仅给我一个预测值! R平方具有NA值! 另外,我不确定是否可以使用cv.glmnet和glmnet进行交叉验证拆分。

任何帮助的想法都会受到赞赏。

已更新

我尝试使用caret

我首先使用LOOCV拆分数据集,因为我希望每个观察都在测试过程中。然后,我使用train函数来完成问题的初衷。

我的代码

data <- read.csv("https://archive.ics.uci.edu/ml/machine-learning-databases/forest-fires/forestfires.csv") 
data<-data[-(3:4)] 
lambda <- 10^seq(-3, 3, length = 100)
predictions <- rep(0,nrow(data))
set.seed(123)
for(i in 1:nrow(data)){
  test.data<-data[i,]
  train.data<-data[-i,]
ridge <- train(
  area ~., data = train.data, method = "glmnet",
  trControl = trainControl("loocv", number = 517),
  tuneGrid = expand.grid(alpha = 0, lambda = lambda))
  coefs=coef(ridge$finalModel, ridge$bestTune$lambda)
  predictions[i] <- ridge %>% predict(test.data)
  RMSE = RMSE(predictions, test.data$area)
  Rsquare = R2(predictions, test.data$area)
  LL<-list(RMSE,Rsquare,coefs,predictions) 
}

此代码还给我以下错误

Error in cor(obs, pred, use = ifelse(na.rm, "complete.obs", "everything")) : 
  incompatible dimensions
In addition: Warning message:
In nominalTrainWorkflow(x = x, y = y, wts = weights, info = trainInfo,  :
  There were missing values in resampled performance measures.

更多更新

我还使用caret包(例如Ridge)编写了以下代码

set.seed(123)
data <- read.csv("forestfires.csv") 
data<-data[-(3:4)]  
lambda.grid <-10^seq(10,-2, length =100)
alpha.grid<- 0 #Ridge 
control <- trainControl(method="LOOCV")
srchGrd = expand.grid(alpha = alpha.grid, lambda = lambda.grid)
lm_model <- train(area ~ . , data=data, trControl=control,tuneGrid=srchGrd,method = 'glmnet')
lm_model
coef(lm_model$finalModel, lm_model$bestTune$lambda)

我现在是吗?

1 个答案:

答案 0 :(得分:1)

好的,既然您已经说了,问题就很明显了。每次循环时,您都会为LL分配一个新值。 LL不会保存所有结果,只是最后一个。试试

LL <- lapply(1:nrFolds, function(k) {
  fold <- which(folds == k)
  data.train <- data[-fold,]
  data.test <- data[fold,]
  x.train <- as.matrix(data.train[-11])
  y.train <- as.matrix(data.train[11])
  x.test <- as.matrix(data.test[-11])
  y.test <- as.matrix(data.test[11])
  cv <- cv.glmnet(x.train, y.train, alpha = 0)
  # cv$lambda.min
  model <- glmnet(x.train, y.train, alpha = 0, lambda = cv$lambda.min)
  coef(model) 
  predictions <- model %>% predict(x.test) %>% as.vector()
  RMSE <- RMSE(predictions, data.test$area)
  Rsquare <- R2(predictions, data.test$area)
  list(CV=cv, model=model, coefs=coef(model), preds=predictions, rmse=RMSE, r2=Rsquare)
})

但是,请查看插入符号包:它可以自动创建折叠和测试。另外,我会事后计算RMSE和R²。

编辑:是,R2为NA。这是因为在上面的代码中,尝试了留一式CV。如上所述,rep_len返回的结果与1:517相同,因此fold基本上是1到517之间的数字,每个data.train都有516列,data.test是向量。因此,predictions是长度为1的向量,并且无法计算R2。

但是,预测正确返回了。

preds <- sapply(LL, function(x) x$preds)

并不是说它们非常好,而是问题在于运行glmnet,而不是如何做出最佳预测。

编辑2 :关于您更新的代码。这就是发生的情况:首先用517个零初始化向量predictions。在循环的第一次迭代中,您告诉插入符号对包含516个样本的训练集进行517 LOO。然后,Caret返回优化的岭模型(以及许多您忽略的信息,例如,每个测试的参数值的RMSE)。然后,对测试集进行预测,这是一个样本。您可以在predictions向量中输入一个样本,该向量现在包含1个预测和516个零。然后,您尝试计算predictions(一个预测的向量和516个零的向量)和测试响应(一个值的向量)之间的R2和RMSE。失败并非偶然。然后,将它们全部存储在名为LL的列表中,下次运行循环时它将被覆盖。

我该怎么做:删除33%的数据作为验证。将剩余的66%用于脱字符,以训练模型(在脱字符中使用LOOCV或K-FOLD来优化参数)。检查插入符的输出;确保查看插入符提供的RMSE(如果使用LOOCV以外的其他值,则查看RSE)。然后,在验证集上测试模型的性能。