为什么在重复测试时,glmnet 调整交叉验证中的 lambda.min 值会发生变化?

机器算法验证 交叉验证 插入符号 网络 可重复研究
2022-04-13 21:27:42

我正在使用glmnet包来构建一个线性回归, = 0.5,以找到最好的[44x15000] ( ), = numeric[44] 一切似乎运行正常,但是当我重新运行该命令时我的方法不正确吗?αλ
xMatrixp>>Ny
λ

cvGlmnet <- cv.glmnet(xMatrix, y, alpha=0.5, nfolds=10)  
 cvGlmnet$lambda.min  [1] 10.24038  
 cvGlmnet$lambda.1se  [1] 17.08198  
cvGlmnet <- cv.glmnet(xMatrix, y, alpha=0.5, nfolds=10)  
 cvGlmnet$lambda.min  [1] 14.85703  
 cvGlmnet$lambda.1se  [1] 17.08198  
cvGlmnet <- cv.glmnet(xMatrix, y, alpha=0.5, nfolds=10)  
 cvGlmnet$lambda.min  [1] 4.865008  
cvGlmnet <- cv.glmnet(xMatrix, y, alpha=0.5, nfolds=10)  
 cvGlmnet$lambda.min  [1] 16.30557
cvGlmnet <- cv.glmnet...  
 cvGlmnet$lambda.min  [1] 14.18176 

除此之外,我还尝试caret了包来调整如果我做对了,给出 = 1 和 = 3。当我按照上面的方法尝试,但使用 = 1 时,值在 5-8 之间移动(至少我尝试过,它们也运行之间变化)。这不应该给一些东西〜3吗?αλobj$bestTuneαλglmnetαλ

我试过这个例子

# generate a dummy dataset with 30 predictors (10 useful & 20 useless) 
y=rnorm(100)
x1=matrix(rnorm(100*20),100,20)
x2=matrix(y+rnorm(100*10),100,10)
x=cbind(x1,x2)

# use crossvalidation to find the best lambda
library(glmnet)
cv <- cv.glmnet(x,y,alpha=1,nfolds=10)
l <- cv$lambda.min

它也略有变化,但没有我的数据变化那么大。是因为我的数据结构/性质吗?

使用插入符号,alpha 值也发生了很大变化(考虑到它只能介于 0 和 1 之间,并且每个极值都是一种完全不同的方法)。有什么线索吗?

4个回答

您获得不同 lambda 值的原因是因为每次调用时 cv.glmnet(xMatrix, y, alpha=0.5, nfolds=10),您实际上是在创建不同的交叉验证折叠。要保留相同的 lambda 值,您需要确保每次都使用相同的交叉验证折叠,因此您可能想在调用之前尝试初始化一个随机数种子cv.glmnet(xMatrix, y, alpha=0.5, nfolds=10)尝试重复运行整个代码块:

set.seed(1)
cvGlmnet <- cv.glmnet(xMatrix, y, alpha=0.5, nfolds=10)
cvGlmnet$lambda.min 

您会看到 lambda 保持不变。因此,您将获得可重复的结果!MichaelJ 在您查询下方的评论中基本上回答了您的问题。

没有数据来重现事物是很难判断的。您没有列出插入符号代码,所以我不确定那里做了什么。

我认为底线是您有 44 个样本和 10 倍 CV,已知具有高方差,不会给您可重复的结果。我建议使用 10FCV 的多次重复(通过trainControl'smethod = "repeatedcv"选项)或转到引导程序并接受您的 RMSE 估计会有点悲观。

高温下,

最大限度

如果您想获得可重复的最佳 lambda & alpha,您可以使用 leave-one-out CV(虽然它不支持 AUC)。

cv <- cv.glmnet(x,y,alpha=1,nfolds=nrow(x))

由于样本的分区是随机生成的,因此 n 倍 CV 给您带来非常大的差异是很正常的。

您的方法对于可重复性不是很好:您set.seed(1)运行一次然后运行cv.glmnet()​​100 次。这些调用中的每一个cv.glmnet()本身都调用了sample()N 次。因此,如果您的数据长度发生变化,重现性就会发生变化。

最好在每次运行之前明确set.seed()正确。或者在运行过程中保持 foldids 不变(使用 caret 或 中的实用程序函数)。