在高维数据分析场景中,比如基因表达数据、用户行为特征或者金融指标,动辄几百上千个特征会让模型变得臃肿,还容易过拟合。LASSO回归正是解决这类问题的利器,它通过在损失函数中加入L1正则化项,把大量不重要的特征系数直接压缩为零,实现了建模和特征筛选的双重目标。本文将带你理解LASSO的底层逻辑,并用Python完整实现一遍。

LASSO回归的原理:为什么L1正则化能稀疏化特征
LASSO的全称是Least Absolute Shrinkage and Selection Operator,翻译过来是最小绝对收缩选择算子。它的损失函数在普通最小二乘的基础上加了一个L1惩罚项,也就是所有回归系数绝对值之和乘以一个惩罚系数alpha。当alpha越大,惩罚力度越强,为了最小化整体损失,模型只能把一部分系数压缩到零。
这里面最关键的问题在于,为什么L1正则化能把系数压到零,而L2正则化(岭回归)只能让系数趋近于零?从几何角度看,L1约束区域是一个菱形,它的尖角指向坐标轴。误差等高线在与菱形相交时,很容易恰好碰到顶点位置,而顶点意味着某些系数正好为零。L2约束区域是一个圆形,表面光滑没有尖角,等高线与圆相切的位置几乎不可能正好落在坐标轴上,所以岭回归只会把系数缩小,却很少让系数精确归零。
用一句话总结:LASSO适合做特征筛选,岭回归适合处理多重共线性。如果你的目标是找出真正有用的特征,LASSO是更好的选择;如果只是想稳定模型系数,岭回归更合适。
用sklearn实现LASSO回归的完整流程
sklearn库中的linear_model.Lasso类提供了开箱即用的实现。下面通过一段完整代码演示从数据准备到系数解读的全过程。
import numpy as np
import pandas as pd
from sklearn.datasets import make_regression
from sklearn.linear_model import Lasso
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
# 构造一个包含100个特征的数据集,其中只有10个特征真正有用
X, y, true_coef = make_regression(
n_samples=500, n_features=100,
n_informative=10, noise=10,
coef=True, random_state=42
)
# LASSO对特征尺度非常敏感,必须先做标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
X_train, X_test, y_train, y_test = train_test_split(
X_scaled, y, test_size=0.3, random_state=42
)
# alpha控制惩罚强度,1.0作为起点
lasso = Lasso(alpha=1.0, max_iter=10000)
lasso.fit(X_train, y_train)
print("训练集R2:", lasso.score(X_train, y_train))
print("测试集R2:", lasso.score(X_test, y_test))
print("被压缩为零的系数个数:", np.sum(lasso.coef_ == 0))
print("保留下来的特征个数:", np.sum(lasso.coef_ != 0))运行这段代码后,你会看到大部分系数变成了零,只有少数特征被保留下来,这正是LASSO稀疏化的直观体现。这里有两个细节需要注意。第一,标准化是必须步骤。L1惩罚对所有系数一视同仁,如果某个特征的数值范围特别大,它对应的系数天然就小,会被错误地惩罚掉。第二,max_iter参数建议调大一些,默认值在复杂数据上可能不收敛,导致sklearn抛出收敛警告。
查看哪些特征被保留下来也很简单,把系数非零的列名提取出来即可。在实际项目中,可以把LASSO当作特征筛选的前置步骤,先用它筛掉无关特征,再用其他模型做最终训练。
alpha参数调优:用LassoCV自动选择最优惩罚强度
alpha是LASSO的灵魂参数,它决定了稀疏化的激进程度。alpha太小,惩罚几乎不起作用,模型退化为普通线性回归;alpha太大,所有系数都被压为零,模型什么都不学。手动尝试不同的alpha值效率很低,sklearn提供了LassoCV类,通过交叉验证自动寻找最优alpha。
from sklearn.linear_model import LassoCV
# 自动在对数空间生成候选alpha,交叉验证选最优
lasso_cv = LassoCV(alphas=np.logspace(-4, 2, 100),
cv=5, max_iter=10000, random_state=42)
lasso_cv.fit(X_train, y_train)
print("最优alpha:", lasso_cv.alpha_)
print("测试集R2:", lasso_cv.score(X_test, y_test))
print("保留特征数:", np.sum(lasso_cv.coef_ != 0))
# 绘制系数随alpha变化的收缩路径
import matplotlib.pyplot as plt
from sklearn.linear_model import lasso_path
alphas, coefs, _ = lasso_path(X_scaled, y, alphas=np.logspace(-3, 2, 100))
plt.plot(np.log10(alphas), coefs.T)
plt.xlabel("log(alpha)")
plt.ylabel("系数值")
plt.title("LASSO系数收缩路径")
plt.show()上面的代码还绘制了系数收缩路径图,这张图非常有参考价值。随着alpha从左到右增大,每条曲线代表一个特征的系数,你会看到系数逐步向零收缩,且不同特征归零的顺序反映了它们的重要性,越晚归零的特征对目标变量的贡献越大。通过观察收缩路径,可以直观判断保留多少个特征比较合理。
除了LassoCV,还有一点值得了解。当特征之间存在强相关关系时,LASSO在两个高度相关的特征之间会随机保留一个、丢弃另一个,表现出一定的不稳定性。这种情况下推荐使用弹性网络(ElasticNet),它在L1和L2之间做了折中,sklearn中对应ElasticNet类,通过参数l1_ratio控制两种正则化的混合比例,兼顾稀疏性和稳定性。
结语
LASSO回归的核心价值在于把特征工程中的人为判断交给了数学约束,通过L1正则化自动完成特征压缩与筛选。落地时记住三个要点:建模前务必标准化特征,用交叉验证确定alpha,并根据特征相关性决定是否切换到弹性网络。掌握这套流程后,面对高维数据就能从容地提取出真正有价值的特征子集。