我尝试使用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)
我现在是吗?
答案 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)。然后,在验证集上测试模型的性能。