R语言中如何向cv.glmnet函数添加随机效应
解决方案
cv.glmnet 本身仅支持独立观测的固定效应惩罚回归,底层优化逻辑没有包含混合模型所需的随机效应方差组分估计、BLUP计算环节,无法直接添加随机效应,直接使用专门适配带惩罚项的混合模型工具即可,对初学者最友好的方案是用glmmLasso包实现,步骤如下:
- 第一步:安装加载对应包
运行install.packages("glmmLasso")完成安装,之后用library(glmmLasso)加载即可。 - 第二步:手动实现交叉验证筛选最优惩罚参数lambda
glmmLasso本身没有封装好的交叉验证函数,实现逻辑非常简单,参考代码如下:
# 以下内容替换成你自己的数据集和对应变量名 # 假设你的数据存储在your_data对象中 # 固定效应自变量名组成的向量 fix_vars <- paste0("x", 1:10) # 随机效应分组变量名(比如受试者ID、班级ID这类聚类标识变量) group_id <- "subj" # 因变量名 y_var <- "y" # 生成待测试的lambda序列,范围要覆盖从所有系数被压缩为0到几乎无压缩的区间 lambda_candidates <- exp(seq(from = 10, to = -3, length.out = 50)) # 5折交叉验证计算每个lambda对应的测试集误差 cv_mse <- sapply(lambda_candidates, function(current_lambda){ # 有嵌套/聚类结构时必须按分组整组划分折,不要拆分组内观测 fold_id <- sample(rep(1:5, length.out = nrow(your_data))) fold_err <- c() for(f in 1:5){ train_set <- your_data[fold_id != f, ] test_set <- your_data[fold_id == f, ] # 拟合模型,示例为连续因变量+随机截距的高斯分布模型 current_fit <- glmmLasso( formula = as.formula(paste(y_var, "~", paste(fix_vars, collapse = "+"))), rnd = list(subj = ~1), # 需要加随机斜率就改成~1 + 对应自变量名 data = train_set, lambda = current_lambda, family = gaussian() # 二分类因变量换binomial(),计数因变量换poisson() ) # 计算测试集预测误差 test_pred <- predict(current_fit, newdata = test_set) fold_err[f] <- mean((test_set[[y_var]] - test_pred)^2) } mean(fold_err) }) # 筛选测试集误差最小的lambda作为最优惩罚参数 best_lambda <- lambda_candidates[which.min(cv_mse)]
- 第三步:用最优lambda在全数据集拟合最终模型
final_model <- glmmLasso( formula = as.formula(paste(y_var, "~", paste(fix_vars, collapse = "+"))), rnd = list(subj = ~1), data = your_data, lambda = best_lambda, family = gaussian() ) # 查看固定效应系数、随机效应方差估计结果 summary(final_model)
注意事项
- 存在聚类/嵌套结构的数据做交叉验证时,必须以聚类组为单位划分折,不能把同一个组的样本拆分到训练和测试集,否则得到的最优lambda会过拟合,误差估计严重偏乐观。
- 不要一开始就设置过于复杂的随机效应结构,样本量不足时随机斜率很难稳定估计,优先从随机截距模型开始尝试。
- 如果你的随机效应结构非常复杂、样本量很大,也可以考虑用
glmmTMB包的惩罚项功能,语法和lme4接近,也支持自定义惩罚结构,但对初学者来说上手门槛比glmmLasso高。
不要尝试魔改
cv.glmnet源码添加随机效应,需要自己实现混合模型的EM迭代、方差组分估计逻辑,代码量和调试成本极高,完全没有必要。
内容的提问来源于stack exchange,提问作者Wenbo Zhang
相关产品推荐
相关产品推荐

