我想使用prostate data
手动执行10倍交叉验证,以了解如何手动执行此操作。我使用elasticnet
包代码。我通过glmnet包估计参数(当然,它也可以执行交叉验证,但我想手动完成)。在分析之后,在我看来,我需要一个不同的标准来选择调整参数而不是最小的cv.error,因为这给出了几乎为空的模型,如果不是这样的话#34;我的错误在哪里?"。 (根据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)
结果:
> coef(fit)
9 x 1 sparse Matrix of class "dgCMatrix"
s0
(Intercept) .
lcavol 0.01926724
lweight .
age .
lbph .
svi .
lcp .
修改
模型直接从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)
结果:
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 .
第二列显示正确的(lambda.1se
)结果。
答案 0 :(得分:2)
你的错误&#34;很难发现:它来自于glmnet
不会使用您自己的lambda
向量的顺序来对结果向量进行排序的事实。
您使用的数据示例:
res <- glmnet(x, y, lambda=lambda)
res$lambda
因此,当您在过程结束时调用命令lambda[which.min(result$cv.error)]
时,您将无法获得与交叉验证错误的最小值相对应的值。此外,它解释了为什么你的图表看起来很奇怪。
一个简单的解决方法是将脚本开头的lambda
声明为递减向量:
lambda = seq(1, 0, 0.02)
最后评论:使用单个lambda时要小心。