r:来自 glmnet 和 caret 的系数对于相同的 lambda 是不同的

Posted

技术标签:

【中文标题】r:来自 glmnet 和 caret 的系数对于相同的 lambda 是不同的【英文标题】:r: coefficients from glmnet and caret are different for the same lambda 【发布时间】:2018-07-17 03:11:19 【问题描述】:

我已经阅读了一些关于此的问答,但我仍然不确定我是否理解,为什么基于相同样本和相同超参数的 glmnet 和插入符号模型的系数略有不同。非常感谢您的解释!

我正在使用插入符号来训练岭回归:

library(ISLR)
Hitters = na.omit(Hitters)
x = model.matrix(Salary ~ ., Hitters)[, -1] #Dropping the intercept column.
y = Hitters$Salary

set.seed(0)
train = sample(1:nrow(x), 7*nrow(x)/10)

library(caret)
set.seed(0)
train_control = trainControl(method = 'cv', number = 10)
grid = 10 ^ seq(5, -2, length = 100)
tune.grid = expand.grid(lambda = grid, alpha = 0)
ridge.caret = train(x[train, ], y[train],
                    method = 'glmnet',
                    trControl = train_control,
                    tuneGrid = tune.grid)
ridge.caret$bestTune
# alpha is 0 and best lambda is 242.0128

现在,我使用上面找到的 lambda(和 alpha)来训练整个数据集的岭回归。最后,我提取系数:

ridge_full <- train(x, y,
                    method = 'glmnet',
                    trControl = trainControl(method = 'none'), 
                    tuneGrid = expand.grid(
                      lambda = ridge.caret$bestTune$lambda, alpha = 0)
                    )
coef(ridge_full$finalModel, s = ridge.caret$bestTune$lambda)

最后,使用完全相同的 alpha 和 lambda,我尝试使用 glmnet 包拟合相同的岭回归 - 并提取系数:

library(glmnet)
ridge_full2 = glmnet(x, y, alpha = 0, lambda = ridge.caret$bestTune$lambda)
coef(ridge_full2)

【问题讨论】:

尝试在交叉验证时询问 当然可以,但是为什么呢?或者您是说这不是编程问题,而是统计计算问题? 可能......我什至无法回答这个问题,因为我对这两个都不太精通:O,但也发帖看看会发生什么! 【参考方案1】:

原因是插入符号没有使用您指定的确切 lambda。您可以通过以下方式检查:

ridge_full$finalModel$lambda

最接近的值为 261.28915 和 238.07694。

当你这样做时

coef(ridge_full$finalModel, s = ridge.caret$bestTune$lambda)

其中 s 为 242.0128,系数是根据实际计算的系数进行插值。

当您向 glmnet 调用提供 lambda 时,模型会返回该 lambda 的精确系数,该系数与插入的插入符号返回的系数略有不同。

为什么会这样:

当您指定一个 alpha 和一个 lambda 以适合所有数据插入符号实际上会适合:

   fit = function(x, y, wts, param, lev, last, classProbs, ...) 
                    numLev <- if(is.character(y) | is.factor(y)) length(levels(y)) else NA

                    theDots <- list(...)

                    if(all(names(theDots) != "family")) 
                      if(!is.na(numLev)) 
                        fam <- ifelse(numLev > 2, "multinomial", "binomial")
                       else fam <- "gaussian"
                      theDots$family <- fam
                    

                    ## pass in any model weights
                    if(!is.null(wts)) theDots$weights <- wts

                    if(!(class(x)[1] %in% c("matrix", "sparseMatrix")))
                      x <- Matrix::as.matrix(x)

                    modelArgs <- c(list(x = x,
                                        y = y,
                                        alpha = param$alpha),
                                   theDots)

                    out <- do.call(glmnet::glmnet, modelArgs)
                    if(!is.na(param$lambda[1])) out$lambdaOpt <- param$lambda[1]
                    out
                  

这是取自here。

在您的示例中,这转换为

fit <- glmnet::glmnet(x, y,
                       alpha = 0)

lambda <- unique(fit$lambda)

这些 lambda 值对应于ridge_full$finalModel$lambda

all.equal(lambda, ridge_full$finalModel$lambda)
#output
TRUE

【讨论】:

以上是关于r:来自 glmnet 和 caret 的系数对于相同的 lambda 是不同的的主要内容,如果未能解决你的问题,请参考以下文章

R caret train glmnet 最终模型 lambda 值与指定不符

变量的顺序改变了 glmnet 中的估计系数

R语言基于glmnet构建分类模型并可视化特征系数(coefficient)以及L1正则化系数(lambda)实战

使用插入符号的岭逻辑回归系数的标准误差

R语言基于glmnet构建Logistic回归模型使用L1正则化并可视化系数及最佳lambda值

R语言glmnet拟合lasso回归模型实战:lasso回归模型的模型系数及可视化lasso回归模型分类评估计算(混淆矩阵accuracyDeviance)