首页 文章

r:来自glmnet和插入符号的系数对于相同的lambda是不同的

提问于
浏览
0

我已经阅读了一些有关这方面的问答,但我仍然不确定我理解为什么基于相同样本和相同超参数的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)

1 回答

  • 2

    原因是您指定的确切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
    

相关问题