R 交叉验证的意外结果

R 交叉验证的意外结果,r,cross-validation,glmnet,lasso-regression,R,Cross Validation,Glmnet,Lasso Regression,我想使用前列腺数据手动执行10倍交叉验证,以了解如何手动执行。我使用elasticnet包进行编码。我通过glmnet包估计了参数(当然,它也可以执行交叉验证,但我希望手动执行)。在分析之后,在我看来,我需要一个不同的标准来选择调整参数,而不是cv.error的最小值,因为这会给出几乎为零的模型,如果不是这样,“我的错误在哪里?”。(根据Tibshirani的原始论文,优化模型有三个变量) 这是密码 library(ElemStatLearn) library(glmnet) x <-

我想使用
前列腺数据
手动执行10倍交叉验证,以了解如何手动执行。我使用
elasticnet
包进行编码。我通过glmnet包估计了参数(当然,它也可以执行交叉验证,但我希望手动执行)。在分析之后,在我看来,我需要一个不同的标准来选择调整参数,而不是cv.error的最小值,因为这会给出几乎为零的模型,如果不是这样,“我的错误在哪里?”。(根据Tibshirani的原始论文,优化模型有三个变量)

这是密码

library(ElemStatLearn)
library(glmnet)

x <- scale(prostate[,1:8],T,T)
y <- scale(prostate[,9],T,F)

lambda = seq(0,1,0.02)

cv.folds <- function(n, folds = 10){
  split(sample(1:n), rep(1:folds, length = n))
}

c.val <-  function(x, y, K = 10, lambda, plot.it = TRUE){
    n <- nrow(x)
    all.folds <- cv.folds(length(y), K)
    residmat <- matrix(0, length(lambda), K)
    for(i in seq(K)) {
      omit <- all.folds[[i]]
      xk <- as.matrix(x[-omit, ])
      yk <- as.vector(y[-omit])
      xg <- x[omit, ]
      yg <- y[omit]
      fit <- glmnet(xk, yk, family="gaussian", 
                    alpha=1, lambda=lambda,standardize = FALSE, intercept = FALSE)
      fit <- predict(fit,newx=xg,lambda=lambda)
      if(length(omit)==1){fit<-matrix(fit,nrow=1)}
      residmat[, i] <- apply((yg - fit)^2, 2, mean)
    }
    cv <- apply(residmat, 1, mean)
    cv.error <- sqrt(apply(residmat, 1, var)/K)
    object<-list(lambda = lambda, cv = cv, cv.error = cv.error)
    if(plot.it) {
      plot(lambda, cv, type = "b", xlab="lambda", ylim = range(cv, cv + cv.error, cv - cv.error))
    invisible(object)
    }
}

result <- c.val(x,y,K = 10,lambda = lambda)
lambda.opt <- lambda[which.min(result$cv.error)]
fit <- glmnet(x, y, family="gaussian", 
              alpha=1, lambda=lambda.opt,standardize = FALSE, intercept = FALSE)
coef(fit)
编辑: 直接从
glmnet
生成的模型

fit.lasso <- glmnet(x, y, family="gaussian", alpha=1,
                    standardize = FALSE, intercept = FALSE)
fit.lasso.cv <- cv.glmnet(x, y, type.measure="mse", alpha=1,
                          family="gaussian",standardize = FALSE, intercept = FALSE)
coef.lambda.min <- coef(fit.lasso.cv,s=fit.lasso.cv$lambda.min)
coef.lambda.1se <- coef(fit.lasso.cv,s=fit.lasso.cv$lambda.1se)
cbind(coef.lambda.min,coef.lambda.1se)
第二列显示了正确的(
lambda.1se
)结果。

您的“错误”很难发现:这是因为
glmnet
不会使用您自己的
lambda
向量的顺序对结果向量进行排序

您使用的数据示例:

res <- glmnet(x, y, lambda=lambda)
res$lambda

最后一句话:使用单个lambda时要小心。

当我运行代码时,我得到一个奇怪的lambda最佳值(~0.98)。此外,我认为所谓的“lambda最佳值”实际上并不对应于最佳MSE,而是“lambda的最大值,以便误差在最小值的1个标准误差范围内。”我按照你的建议编辑了代码。结果似乎仍然不正确。我通过完全
glmnet
添加生成正确模型的代码。但是,正如我们所看到的,
lambda.min
生成的模型比理论上预期的
lambda1se
模型具有更多的变量。我想我看到了我的错误。问题源于
cv
cv.error
的定义。非常感谢您抽出时间。
9 x 2 sparse Matrix of class "dgCMatrix"
                      1         1
(Intercept)  .          .        
lcavol       0.59892674 0.5286355
lweight      0.23669159 0.1201279
age         -0.06979581 .        
lbph         0.09392021 .        
svi          0.24620007 0.1400748
lcp          .          .        
gleason      0.00346421 .        
pgg45        0.06631013 . 
res <- glmnet(x, y, lambda=lambda)
res$lambda
lambda = seq(1, 0, 0.02)