r:对于相同的 lambda,来自 glmnet 和 caret 的系数不同
r: coefficients from glmnet and caret are different for the same lambda
我已经阅读了一些关于此的问答,但我仍然不确定我是否理解,为什么基于相同样本和相同超参数的 glmnet 和 caret 模型的系数略有不同。非常感谢您的解释!
我正在使用插入符来训练岭回归:
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)
原因是插入符号未使用您指定的确切 lambda。您可以通过以下方式查看:
ridge_full$finalModel$lambda
最接近的值是 261.28915 和 238.07694。
当你这样做时
coef(ridge_full$finalModel, s = ridge.caret$bestTune$lambda)
其中 s 是 242.0128,系数是从实际计算的系数中插入的。
当您向 glmnet 提供 lambda 时调用模型 returns 该 lambda 的精确系数与插值的插入符号 returns.
仅略有不同
为什么会这样:
当您指定一个 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
我已经阅读了一些关于此的问答,但我仍然不确定我是否理解,为什么基于相同样本和相同超参数的 glmnet 和 caret 模型的系数略有不同。非常感谢您的解释!
我正在使用插入符来训练岭回归:
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)
原因是插入符号未使用您指定的确切 lambda。您可以通过以下方式查看:
ridge_full$finalModel$lambda
最接近的值是 261.28915 和 238.07694。
当你这样做时
coef(ridge_full$finalModel, s = ridge.caret$bestTune$lambda)
其中 s 是 242.0128,系数是从实际计算的系数中插入的。
当您向 glmnet 提供 lambda 时调用模型 returns 该 lambda 的精确系数与插值的插入符号 returns.
仅略有不同为什么会这样:
当您指定一个 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