LASSO回归特征选择
一句话概述:LASSO(Least Absolute Shrinkage and Selection Operator)通过L1正则化惩罚将不重要特征的系数压缩到零,实现自动特征选择,是生信中高维数据降维和生物标志物筛选的核心方法。
核心知识点速查表
| 概念 | 说明 |
|---|
| LASSO | L1正则化回归(白话:自动帮你挑最重要的变量) |
| L1正则化 | 惩罚项为系数绝对值之和,会产生稀疏解 |
| Lambda(λ) | 正则化强度参数,λ越大→选的变量越少 |
| lambda.min | 使交叉验证误差最小的λ值 |
| lambda.1se | 在最小误差1个标准误内最简约的λ值(推荐) |
| 交叉验证 | 用CV选择最优λ,避免过拟合 |
| 弹性网络 | L1+L2混合正则化(alpha=0.5时) |
一、LASSO回归原理
# 普通线性回归:最小化 RSS = Σ(y - Xβ)²
# LASSO回归: 最小化 RSS + λ × Σ|βj|
# ↑ L1惩罚项
# λ=0: 等同于普通回归(不做选择)
# λ→∞: 所有系数→0(选择太严格)
# 关键:找到合适的λ,在拟合度和简约性之间平衡
# 白话解释:
# 就像公司裁员,λ是裁员力度
# λ小→不怎么裁人,λ大→大规模裁员
# lambda.1se→在完成工作的前提下用最少的人
二、R语言实操
2.1 基本LASSO回归
# === LASSO回归 ===
library(glmnet)
# 准备数据
x <- as.matrix(gene_expr) # 特征矩阵(基因表达)
y <- clinical$response # 响应变量
# 交叉验证选择最优lambda
set.seed(42) # 设置随机种子(可重复)
cv_fit <- cv.glmnet(
x, y,
family = "binomial", # 二分类用binomial,连续用gaussian
alpha = 1, # alpha=1是LASSO(0=Ridge,0-1=弹性网络)
nfolds = 10, # 10折交叉验证
type.measure = "class" # 评估指标:分类错误率
)
# 可视化lambda选择
plot(cv_fit) # ★lambda vs CV误差图
abline(v=log(cv_fit$lambda.min), lty=2, col="red") # 最优lambda
abline(v=log(cv_fit$lambda.1se), lty=2, col="blue") # 1se lambda
# 查看最优lambda
cat("lambda.min:", cv_fit$lambda.min, "\n") # 最小误差的lambda
cat("lambda.1se:", cv_fit$lambda.1se, "\n") # 1se规则的lambda
# 提取选中的特征
coef_min <- coef(cv_fit, s="lambda.min") # lambda.min的系数
coef_1se <- coef(cv_fit, s="lambda.1se") # lambda.1se的系数
# 非零系数的变量就是被选中的
selected_min <- rownames(coef_min)[coef_min[,1] != 0][-1] # 去掉截距
selected_1se <- rownames(coef_1se)[coef_1se[,1] != 0][-1]
cat("lambda.min选中:", length(selected_min), "个变量\n")
cat("lambda.1se选中:", length(selected_1se), "个变量\n")
print(selected_1se) # 打印选中的变量
2.2 LASSO-Cox生存分析
# === LASSO-Cox(生信最常用场景) ===
library(glmnet)
library(survival)
# 准备数据
x <- as.matrix(gene_expr) # 基因表达矩阵
y <- Surv(clinical$time, clinical$status) # 生存数据
# 交叉验证
set.seed(42)
cv_cox <- cv.glmnet(
x, y,
family = "cox", # Cox模型
alpha = 1, # LASSO
nfolds = 10 # 10折CV
)
plot(cv_cox) # lambda选择图
# 提取选中的基因
coef_cox <- coef(cv_cox, s="lambda.1se")
selected_genes <- rownames(coef_cox)[coef_cox[,1] != 0]
cat("选中", length(selected_genes), "个预后基因:\n")
print(selected_genes)
# 计算风险评分
risk_score <- predict(cv_cox, newx=x, s="lambda.1se", type="response")
# 分高低风险组
median_risk <- median(risk_score)
risk_group <- ifelse(risk_score > median_risk, "High", "Low")
# KM生存曲线
library(survminer)
fit <- survfit(y ~ risk_group)
ggsurvplot(fit, pval=TRUE, risk.table=TRUE,
palette=c("red", "blue"),
legend.labs=c("High Risk", "Low Risk"))
2.3 系数路径图
# === 系数路径图(展示特征选择过程) ===
fit <- glmnet(x, y, family="cox", alpha=1) # 拟合不同lambda
# 绘制系数路径
plot(fit, xvar="lambda", label=TRUE) # 按lambda
plot(fit, xvar="norm", label=TRUE) # 按L1范数
plot(fit, xvar="dev", label=TRUE) # 按偏差比
# ★添加交叉验证结果
abline(v=log(cv_cox$lambda.1se), lty=2) # 1se位置
title("LASSO Coefficient Path")
三、Python实操
# === Python LASSO回归 ===
from sklearn.linear_model import LassoCV, LogisticRegressionCV
from sklearn.preprocessing import StandardScaler
import numpy as np
import pandas as pd
# 准备数据
X = gene_expr_df.values # 特征矩阵
y = clinical_df['response'].values # 目标变量
# 标准化(LASSO对量纲敏感!)
scaler = StandardScaler() # 创建标准化器
X_scaled = scaler.fit_transform(X) # 标准化
# LASSO回归(连续变量)
lasso_cv = LassoCV(
alphas=None, # 自动选择alpha范围
cv=10, # 10折交叉验证
random_state=42, # 随机种子
max_iter=10000 # 最大迭代次数
)
lasso_cv.fit(X_scaled, y) # 拟合
# 查看结果
print(f"最优alpha: {lasso_cv.alpha_:.4f}")
selected = np.where(lasso_cv.coef_ != 0)[0] # 非零系数的索引
print(f"选中 {len(selected)} 个特征")
for idx in selected:
print(f" {gene_expr_df.columns[idx]}: coef={lasso_cv.coef_[idx]:.4f}")
# LASSO分类(二分类)
logistic_lasso = LogisticRegressionCV(
penalty='l1', # L1正则化=LASSO
solver='saga', # 支持L1的求解器
cv=10, # 10折CV
random_state=42,
max_iter=10000
)
logistic_lasso.fit(X_scaled, y) # 拟合
四、面试高频考点
Q1: LASSO和Ridge回归的区别?
| LASSO(L1) | Ridge(L2) |
|---|
| 惩罚项 | Σ|βj| | Σβj² |
| 特征选择 | 能(系数可压缩到0) | 不能(系数只能接近0) |
| 适用场景 | 需要特征选择时 | 特征都重要但要防过拟合时 |
| 多重共线性 | 从相关变量中只选一个 | 保留所有变量但缩小系数 |
| 白话 | 裁员(直接砍人) | 降薪(每人少发点但不裁) |
Q2: lambda.min和lambda.1se选哪个?
- lambda.min:误差最小,选的变量多,预测最准但可能过拟合
- lambda.1se:在误差可接受范围内最简约,变量更少,更泛化
- 推荐:一般用lambda.1se(生信文章常用,模型更简约更有临床价值)
Q3: LASSO在生信中的典型应用?
- 从数千个基因中筛选预后标志物(LASSO-Cox)
- 构建诊断模型(LASSO-Logistic)
- 多组学数据降维
- 免疫基因评分模型构建
常见报错与解决
| 报错 | 原因 | 解决方案 |
|---|
All coefficients are zero | lambda太大 | 用lambda.min而非lambda.1se |
Convergence warning | 未收敛 | 增加max.iter或标准化数据 |
选的变量太多 | lambda太小 | 用lambda.1se |
不同随机种子结果不同 | LASSO对数据敏感 | 多次运行取交集 |
速查表
# === LASSO速查(R语言) ===
library(glmnet)
# 分类
cv_fit <- cv.glmnet(x, y, family="binomial", alpha=1, nfolds=10)
# 回归
cv_fit <- cv.glmnet(x, y, family="gaussian", alpha=1, nfolds=10)
# 生存
cv_fit <- cv.glmnet(x, Surv(time,status), family="cox", alpha=1)
# 提取结果
plot(cv_fit) # lambda选择图
coef(cv_fit, s="lambda.1se") # 系数
selected <- rownames(coef)[coef[,1]!=0] # 选中的变量
# 弹性网络: alpha=0.5 (LASSO和Ridge的混合)