You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在R中如何用cv.glmnet选定的单个lambda执行Lasso的5折交叉验证?

嘿,这个问题我之前也碰到过!其实cv.glmnetglmnet不是不接受单个lambda值,只是默认流程没法直接拿到你想要的每折变量选择结果。最灵活的解决方案是手动实现固定lambda的5折交叉验证,这样你能完全掌控每一步,还能轻松提取每折选入的预测变量。下面是具体的操作步骤和代码示例:

具体实现步骤

1. 准备好数据和预先选定的lambda.min

首先确保你已经有了新的数据集(比如new_X是预测变量矩阵,new_y是响应变量),以及之前用cv.glmnet()得到的最优lambda值lambda_opt(也就是你说的lambda.min)。

2. 生成5折交叉验证的折叠索引

我们需要先把数据集拆分成5个互不重叠的折叠,保证每次验证的样本不重复。可以用caret包的工具,或者基础R代码实现:

# 先安装caret包(如果没装的话):install.packages("caret")
library(caret)
set.seed(123) # 设置随机种子,让结果可重复
folds <- createFolds(new_y, k = 5, list = TRUE)

要是不想用caret,基础R也能搞定:

set.seed(123)
n <- length(new_y)
fold_ids <- sample(rep(1:5, length.out = n))
folds <- lapply(1:5, function(k) which(fold_ids == k))

3. 遍历每个折叠,拟合Lasso并提取选入变量

接下来循环处理每个折叠:用当前折叠的训练集拟合固定lambda的Lasso,然后提取非零系数对应的变量名:

library(glmnet)
# 初始化列表存储每折的结果
fold_selected_vars <- list()

for (k in 1:5) {
  # 拆分当前折叠的训练集和验证集
  train_X <- new_X[-folds[[k]], ]
  train_y <- new_y[-folds[[k]]]
  
  # 用固定的lambda_opt拟合Lasso(alpha=1就是Lasso)
  lasso_fit <- glmnet(train_X, train_y, lambda = lambda_opt, alpha = 1)
  
  # 提取非零系数的变量名
  coef_matrix <- coef(lasso_fit)
  selected_vars <- rownames(coef_matrix)[coef_matrix != 0]
  
  # 去掉截距项(如果不需要的话)
  selected_vars <- setdiff(selected_vars, "(Intercept)")
  
  # 把结果存入列表
  fold_selected_vars[[paste0("Fold_", k)]] <- selected_vars
}

4. 查看和分析结果

现在fold_selected_vars里就存了每折选入的变量,你可以直接打印查看,或者统计变量的入选频率:

# 打印每折的选入变量
for (fold_name in names(fold_selected_vars)) {
  cat(fold_name, "选入的变量:\n")
  print(fold_selected_vars[[fold_name]])
  cat("\n")
}

# 统计每个变量在多少折里被选入(需要dplyr和tidyr包)
library(dplyr)
library(tidyr)
bind_rows(lapply(fold_selected_vars, function(vars) tibble(variable = vars)), .id = "fold") %>%
  count(variable, sort = TRUE)
补充:用cv.glmnet的替代方案

如果你坚持想用cv.glmnet(),其实可以传入只包含lambda_opt的序列,然后通过它的fit.preval属性提取每折的拟合结果,但这种方式不如手动实现直观:

cv_fit <- cv.glmnet(new_X, new_y, lambda = c(lambda_opt), alpha = 1, nfolds = 5)
# 每折的拟合对象存在fit.preval里,遍历提取变量
fold_selected_vars_alt <- lapply(cv_fit$fit.preval, function(fit) {
  coefs <- coef(fit, s = lambda_opt)
  setdiff(rownames(coefs)[coefs != 0], "(Intercept)")
})

不过手动实现的方式更灵活,比如你需要在训练前对数据做标准化、预处理等操作时,能更方便地嵌入到流程里。

内容的提问来源于stack exchange,提问作者D_C

火山引擎 最新活动