R语言glmnet模型如何获取全部非零系数?
解决glmnet(Ridge回归)出现零系数并保留全部非零系数的问题
为什么会出现零系数?
你的模型设置了lower.limits = 0,搭配alpha=0的Ridge回归:
- Ridge回归本身的L2惩罚只会缩小系数,不会将任何系数压缩到0。但
lower.limits = 0强制所有系数不能为负,当模型计算出某个系数为负数时,就会被截断为0,这是你看到零系数的核心原因。 - 如果同时调整了
penalty.factor给某些变量设置了极高的惩罚权重,也会让系数被过度压缩,结合非负约束后更容易变成0。
如何获取全部非零系数?
根据你的需求,有两种解决方案:
1. 移除非负约束(优先推荐,若业务允许)
直接删除lower.limits = 0参数,Ridge回归会自动保留所有非零系数:
model_1 <- cv.glmnet( X_factors %>% as.matrix(), data_for_modeling$salary %>% log(), family = "gaussian", alpha = 0 ) # 获取全部非零系数 coef_all_nonzero <- coef(model_1, s = model_1$lambda.min)
此时所有系数都会是非零值(因为L2惩罚不会将任何系数压到0)。
2. 保留非负约束,但调整惩罚强度
如果你必须要求系数非负,可以通过选择更小的lambda值来降低惩罚力度,避免系数被截断为0:
- 默认
cv.glmnet会选择lambda.min(交叉验证误差最小的lambda)或lambda.1se(误差在1倍标准差内的最大lambda)。你可以尝试用更小的lambda,甚至直接用s=0(对应无正则化的普通线性回归,此时系数完全不被压缩):
# 使用lambda.min获取系数(若仍有零,尝试更小的lambda) coef_nonzero <- coef(model_1, s = model_1$lambda.min) # 或者用无正则化的线性回归(s=0) coef_no_reg <- coef(model_1, s = 0)
另外,如果你想让特定变量不被惩罚,可以给penalty.factor对应位置设为0,比如让第3个变量不被惩罚:
model_1 <- cv.glmnet( X_factors %>% as.matrix(), data_for_modeling$salary %>% log(), family = "gaussian", alpha = 0, lower.limits = 0, penalty.factor = c(1,1,0,1,...) # 第3个变量惩罚因子为0 )
关于offset参数的说明
offset是一个固定系数为1的预测项,它不会被模型拟合,也不参与正则化。在你的高斯回归场景中,设置offset = vec相当于让模型拟合:log(salary) - vec ~ X_factors
它的作用是引入已知的、不需要估计的调整项(比如标准化后的某个固定值),和系数是否为零没有直接关联,不是解决当前问题的正确方向。
内容的提问来源于stack exchange,提问作者Dmitrii Asoskov
相关产品推荐
相关产品推荐

