LASSO回归变量选择¶
一句话概述:LASSO回归通过L1惩罚项自动将不重要变量的系数压缩为零,是高维数据(基因数>>样本数)中筛选关键变量建立预测模型的金标准方法。
核心知识点速览¶
| 概念 | 白话解释 |
|---|---|
| 正则化 | 给模型加"惩罚",防止它太贪心(过拟合) |
| LASSO(L1) | 惩罚=系数绝对值之和,能把无关变量的系数压到0(自动选变量) |
| Ridge(L2) | 惩罚=系数平方和,系数会变小但不会变成0(不做变量选择) |
| ElasticNet | LASSO+Ridge的混合,兼顾两者优点 |
| lambda(λ) | 惩罚力度参数,λ越大筛掉越多变量 |
| lambda.min | 交叉验证误差最小的λ值(保留更多变量) |
| lambda.1se | 误差在最小值1个标准误内的最大λ(更简约的模型) |
| 交叉验证(CV) | 把数据分N份,轮流做训练和测试,找最优λ |
| alpha | 控制L1/L2比例:alpha=1是LASSO,alpha=0是Ridge |
| glmnet | R中做LASSO/Ridge/ElasticNet的标准包(2026版) |
一、三种正则化方法对比¶
假设你在装修房子,有100个装饰品可选:
Ridge(L2):每个装饰品都摆上,但都缩小了
→ 所有变量保留,系数都变小
LASSO(L1):只选20个摆上,其他80个扔掉
→ 自动选变量,不重要的系数=0
ElasticNet:选30个摆上,但有些缩小
→ 介于两者之间,适合相关变量多的情况
| 特征 | Ridge (L2) | LASSO (L1) | ElasticNet |
|---|---|---|---|
| alpha参数 | 0 | 1 | 0-1之间 |
| 变量选择 | 不做 | 能做 | 能做 |
| 共线性处理 | 好 | 差(随机选一个) | 好 |
| 适用场景 | 所有变量都有用 | 需要选变量 | 变量间高度相关 |
| 生信常用度 | 较少 | 最常用 | 次常用 |
二、glmnet实操¶
2.1 安装和准备¶
# 安装glmnet(2026最新版)
install.packages("glmnet") # 安装
library(glmnet) # 加载
# 准备数据(以基因表达预测疾病为例)
# x: 预测变量矩阵(行=样本,列=基因)
# y: 响应变量(0/1的疾病状态)
# 读取数据
expr_data <- read.csv("expression_matrix.csv", row.names = 1) # 表达矩阵
# 转为矩阵格式(glmnet要求)
x <- as.matrix(expr_data[, -1]) # 预测变量(去掉第一列如果是标签)
y <- expr_data[, 1] # 响应变量
# 或者用model.matrix(处理分类变量更方便)
# x <- model.matrix(y ~ ., data = expr_data)[, -1]
2.2 LASSO回归(分类问题)¶
# ===== 步骤1:交叉验证找最优lambda =====
set.seed(42) # 设置随机种子(保证可重复)
cv_fit <- cv.glmnet(
x = x, # 预测变量矩阵
y = y, # 响应变量
family = "binomial", # 二分类(逻辑回归);连续变量用"gaussian"
alpha = 1, # alpha=1 是LASSO
nfolds = 10, # 10折交叉验证
type.measure = "auc" # 用AUC作为评价指标;也可用"deviance"
)
# 画交叉验证图
plot(cv_fit) # X轴=log(lambda),Y轴=AUC,上方数字=非零系数个数
# 左虚线 = lambda.min(最优性能)
# 右虚线 = lambda.1se(简约模型)
# 查看两个关键lambda值
cat("lambda.min:", cv_fit$lambda.min, "\n") # 最优lambda
cat("lambda.1se:", cv_fit$lambda.1se, "\n") # 简约lambda
# ===== 步骤2:提取系数(选出的变量) =====
# 用lambda.1se(更简约,推荐发文章)
coef_1se <- coef(cv_fit, s = "lambda.1se") # 提取系数
# 用lambda.min(更多变量,性能更好)
coef_min <- coef(cv_fit, s = "lambda.min")
# 找出非零系数的变量(即被选中的基因)
selected_genes <- rownames(coef_1se)[which(coef_1se != 0)] # 非零系数
selected_genes <- selected_genes[selected_genes != "(Intercept)"] # 去掉截距项
cat("选出的基因数:", length(selected_genes), "\n")
print(selected_genes) # 打印选出的基因
# ===== 步骤3:用选出的变量重新建模 =====
# 方法1:直接用glmnet的预测
pred_prob <- predict(cv_fit, newx = x, s = "lambda.1se", type = "response")
# type="response"返回概率值(0-1之间)
# 方法2:用选出的变量建logistic回归
selected_data <- data.frame(y = y, x[, selected_genes])
final_model <- glm(y ~ ., data = selected_data, family = binomial)
summary(final_model) # 查看系数和p值
2.3 LASSO-Cox回归(生存分析)¶
# 在生存分析中用LASSO选变量(非常常见)
library(survival) # 加载survival包
# 准备Surv对象
y_surv <- Surv(time = clinical$time, event = clinical$status) # 生存时间和事件
# 交叉验证找最优lambda
cv_cox <- cv.glmnet(
x = x, # 基因表达矩阵
y = y_surv, # Surv对象
family = "cox", # Cox回归
alpha = 1, # LASSO
nfolds = 10, # 10折CV
type.measure = "C" # C-index作为评价指标
)
# 画图和提取系数
plot(cv_cox)
coef_cox <- coef(cv_cox, s = "lambda.min") # Cox常用lambda.min
selected_cox <- rownames(coef_cox)[which(coef_cox != 0)]
cat("选出的基因数:", length(selected_cox), "\n")
# 计算风险评分
risk_score <- predict(cv_cox, newx = x, s = "lambda.min", type = "link")
# risk_score越高,风险越大
2.4 ElasticNet¶
# 当基因间高度共线性时,用ElasticNet
# 先找最优alpha
alpha_values <- seq(0.1, 0.9, by = 0.1) # 测试多个alpha值
cv_results <- list()
for (a in alpha_values) {
set.seed(42)
cv_results[[as.character(a)]] <- cv.glmnet(
x = x, y = y, family = "binomial",
alpha = a, nfolds = 10, type.measure = "auc"
)
}
# 找AUC最高的alpha
best_auc <- sapply(cv_results, function(fit) max(fit$cvm))
best_alpha <- alpha_values[which.max(best_auc)]
cat("最优alpha:", best_alpha, "\n")
# 用最优alpha重新拟合
cv_enet <- cv.glmnet(x, y, family = "binomial", alpha = best_alpha, nfolds = 10)
三、结果可视化¶
3.1 系数路径图¶
# 画系数随lambda变化的路径
fit <- glmnet(x, y, family = "binomial", alpha = 1) # 拟合模型
plot(fit, xvar = "lambda", label = TRUE) # 系数路径图
# X轴=log(lambda),Y轴=系数值
# 每条线是一个基因,lambda增大时系数逐渐归零
abline(v = log(cv_fit$lambda.1se), lty = 2) # 标记选择的lambda
3.2 变量重要性图¶
# 画选出变量的系数条形图
library(ggplot2)
coef_df <- data.frame(
Gene = selected_genes,
Coefficient = as.numeric(coef_1se[selected_genes, ])
)
coef_df <- coef_df[order(abs(coef_df$Coefficient), decreasing = TRUE), ]
ggplot(coef_df, aes(x = reorder(Gene, abs(Coefficient)), y = Coefficient)) +
geom_bar(stat = "identity", fill = ifelse(coef_df$Coefficient > 0, "red", "blue")) +
coord_flip() + # 横向条形图
labs(x = "Gene", y = "LASSO Coefficient",
title = "Selected Genes by LASSO") +
theme_minimal()
四、lambda.min vs lambda.1se¶
lambda.min: 交叉验证误差最小的λ
优点:模型性能最好
缺点:可能选太多变量(过拟合风险)
适用:探索性分析、预测为主
lambda.1se: 误差在最小值±1SE范围内的最大λ
优点:模型更简洁,泛化更好
缺点:可能丢失一些有用变量
适用:发文章、需要简洁模型
生信论文推荐:
- 发现生物标志物 → lambda.1se(选变量更严格)
- 构建预测模型 → lambda.min(保留更多信息)
- 实际用时画两个λ的结果对比,讨论差异
常见报错与解决¶
| 报错信息 | 原因 | 解决方案 |
|---|---|---|
x should be a matrix | 输入不是矩阵 | as.matrix()转换 |
number of observations differ | x和y行数不同 | 检查样本数是否一致 |
NA/NaN/Inf in x | 数据有缺失或异常值 | 预处理移除NA/Inf |
All used predictors have zero variance | 某些基因表达完全不变 | 预先过滤零方差基因 |
option grouped=FALSE | 分类变量组内样本太少 | 增加样本或合并类别 |
Error in predict: newx has wrong dimensions | 预测数据列数不对 | 确保新数据有相同的列 |
速查表¶
# LASSO快速流程
as.matrix(x) → cv.glmnet(x, y, alpha=1) → plot() → coef(s="lambda.1se")
# 三种回归
alpha = 1: LASSO(选变量)
alpha = 0: Ridge(不选变量)
alpha = 0.5: ElasticNet(折中)
# family参数
"gaussian": 连续变量(线性回归)
"binomial": 二分类(逻辑回归)
"cox": 生存分析(Cox回归)
"multinomial": 多分类
"poisson": 计数数据
# 两个关键lambda
lambda.min: 性能最好
lambda.1se: 模型最简洁(推荐)
# 常用评价指标(type.measure)
"deviance": 偏差(默认)
"auc": AUC(二分类推荐)
"C": C-index(Cox推荐)
"mse": 均方误差(连续变量)
面试高频问题¶
Q1:LASSO为什么能做变量选择?¶
答:LASSO的L1惩罚项是系数绝对值之和。从几何角度看,L1惩罚的约束区域是菱形(有尖角),而最优解往往落在尖角上,尖角处某些系数恰好为零。L2惩罚的约束区域是圆形(没有尖角),所以系数不会变成零。简单说:LASSO的"菱形约束"让系数更容易触碰到坐标轴,从而被压到零。
Q2:lambda.min和lambda.1se怎么选?¶
答:lambda.min是交叉验证误差最小的λ,模型复杂但性能最好。lambda.1se是误差在最小值一个标准误范围内的最大λ,选出更少的变量但模型更简洁、泛化更好。发文章通常用lambda.1se(更不容易过拟合),构建预测模型优先性能则用lambda.min。建议两个都报告并讨论差异。
Q3:LASSO和ElasticNet什么时候用哪个?¶
答:当预测变量之间相关性不高时用LASSO(alpha=1);当变量高度共线性时用ElasticNet(alpha=0.5左右)。因为LASSO面对一组相关变量时倾向于只选一个(其他压为零),而ElasticNet会选一组。基因表达数据中共表达很常见,所以ElasticNet在生信中越来越受青睐。
Q4:LASSO在生信中最常用的场景是什么?¶
答:①生物标志物筛选——从上千个基因中选出少数关键基因;②构建预后模型——LASSO-Cox回归选基因+计算风险评分;③诊断模型——LASSO-logistic回归建立疾病预测模型;④与列线图结合——选出的变量用于构建临床预测模型。LASSO+Cox+列线图是临床生信论文的"三件套"。
Q5:LASSO回归有什么局限性?¶
答:①变量选择不稳定——样本略有变化,选出的变量可能不同(可用bootstrap+LASSO提高稳定性);②对共线性敏感——高相关变量中只随机选一个(用ElasticNet解决);③不适合因果推断——选出的变量不一定有因果关系,只是预测相关;④需要足够样本——样本太少时交叉验证不可靠。