L1与L2正则化深度解析:从范数几何到Lasso与Ridge实战选型
做机器学习这些年我越来越觉得数学基础这东西就像盖楼时的钢筋——平时看不见但楼能盖多高、扛不扛得住震全看它。很多朋友学正则化的时候背下了“L1产生稀疏解、L2让权重变小”这句话就以为懂了结果一到调参现场就懵为什么我的Lasso把有用特征也砍了为什么Ridge的系数压不下去为什么同一个数据集换个量纲结果天差地别这些问题根子都不在代码而在对L1范数和L2范数的理解深度上。这篇内容我想把L1范数对应曼哈顿距离和Lasso回归、L2范数对应欧氏距离和Ridge回归这条线索彻底捋一遍。不只是讲公式而是讲清楚它们为什么长这样、几何上意味着什么、实操中怎么选、踩过哪些坑。适合已经会用sklearn跑模型、但想搞明白背后逻辑的朋友也适合刚接触正则化、想一次学扎实的新手。读完你应该能自己判断面对一个具体任务到底该上L1、L2还是两者混着来。1. 从距离度量到正则项这条线索是怎么串起来的1.1 范数本质上是“衡量大小”的尺子先把范数这个词祛魅。范数norm说白了就是给向量量个“长度”只不过不同的量法对应不同的尺子。L1范数把每个分量的绝对值加起来L2范数把每个分量平方求和再开根号。放到二维平面上从原点到点(a,b)L1范数算出来是|a||b|L2范数是根号下a²b²。前者对应的是你走街区路网的实际路程——只能横着走再竖着走不能斜穿后者是两点之间的直线距离。这就是曼哈顿距离和欧氏距离这两个名字的由来一个像在曼哈顿方格街区里绕一个是鸟飞直线。这个几何直觉特别重要因为后面Lasso和Ridge的所有行为差异几乎都能从“尺子形状不同”推出来。L1的等值线是菱形高维是菱形体的多面体L2的等值线是圆高维是球面。记住这个形状后面讲稀疏性的时候你会感谢自己。1.2 正则化到底在解决什么问题很多人把正则化当成“防止过拟合的魔法开关”其实它的本质是在损失函数里加一个惩罚项逼模型在“拟合训练数据”和“保持参数简单”之间做权衡。原始的最小二乘只关心残差平方和模型为了把训练误差压到最低可以把系数撑得非常大尤其在特征多、样本少或者特征之间高度相关的时候系数会剧烈震荡泛化能力崩掉。加正则项就是给系数上“紧箍咒”不让它乱跑。用公式说普通线性回归最小化的是残差平方和RSS。Lasso在它后面加一个λ乘以系数绝对值之和Ridge加的是λ乘以系数平方和。这个λ就是调节惩罚力度的旋钮λ越大惩罚越狠系数被压得越厉害。理解这一点你就明白调参调的其实是“拟合精度”和“模型简洁度”的平衡点。1.3 为什么偏偏是L1和L2这两种范数理论上任何范数都能当正则项但L1和L2之所以成为主流是因为它们在优化上都有良好性质。L2处处可导求梯度干净利落闭式解都能写出来L1在零点不可导需要次梯度或者坐标下降来处理但换来的稀疏性是别的范数给不了的。至于L0范数数非零元素的个数它虽然最直接地表达“稀疏”但组合优化问题NP难实际没法用所以L1成了L0最紧的凸松弛。这个“凸松弛”的思路是理解Lasso的理论钥匙后面会展开。2. L1范数与Lasso稀疏性从哪来2.1 几何视角菱形顶点为什么偏爱零这是我最想讲清楚的一段因为它是Lasso稀疏性的根。把Lasso的目标函数写成两部分残差平方和的等高线是一圈圈椭圆L1惩罚项的等值线是菱形。最优解出现在椭圆和菱形第一次相切的地方。关键在于菱形的形状——它有尖尖的顶点而且顶点正好落在坐标轴上。椭圆扩张过来很容易先碰到某个顶点而不是边一旦切在顶点就意味着一部分坐标恰好是零。维度越高菱形体的“尖角”越多碰到坐标轴方向解的概率越大所以高维场景下Lasso特别容易产出稀疏解。这不是玄学是几何必然。你可以自己画个二维图验证固定一个椭圆让它从外往里缩看它最先接触菱形的位置十有八九在顶点附近。2.2 代数视角软阈值与特征筛选从坐标下降的角度看Lasso对每个系数的更新带一个软阈值操作把最小二乘估计往零的方向推λ那么多推过头就归零。这个机制天然带“截断”效果——小的系数直接被抹平大的系数被整体缩小。所以Lasso不只是缩小系数它真的在做特征选择把不重要的特征权重设成精确的零。这一点在实际业务里价值巨大。比如你手上几百个特征老板要你给个“到底哪些因素在起作用”的清单Lasso直接给你答案不用再跑一遍特征重要性分析。我做过一个用户流失预测的项目原始特征一百多个Lasso跑完只剩二十来个非零模型还更稳了汇报的时候也好解释。2.3 实操用坐标下降跑一个Lassosklearn里Lasso默认就是用坐标下降实现的下面这段可以直接抄from sklearn.linear_model import Lasso from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split import numpy as np # 假设 X, y 已经准备好 scaler StandardScaler() X_scaled scaler.fit_transform(X) X_train, X_test, y_train, y_test train_test_split( X_scaled, y, test_size0.2, random_state42 ) model Lasso(alpha0.01, max_iter10000, tol1e-4) model.fit(X_train, y_train) coef model.coef_ nonzero_idx np.where(coef ! 0)[0] print(f非零系数个数: {len(nonzero_idx)} / {len(coef)}) print(f测试集R2: {model.score(X_test, y_test)})这里alpha就是λ。注意几个参数max_iter要给够坐标下降收敛可能慢tol控制收敛精度标准化一定要做原因下一节讲。2.4 注意事项Lasso的三个坑第一个坑是特征高度相关时Lasso会随机挑一个留下、把其他的砍掉结果不稳定换个随机种子选的特征就变了。这时候别迷信它的选择结果要么先做相关性分析去冗余要么改用弹性网。第二个坑是特征数远大于样本数时Lasso最多只能选出样本量那么多个非零特征这是它的理论上限别指望它从一万个特征里挑出几千个。第三个坑是alpha的量级。很多人直接套0.1、1这种值结果模型全零或者完全没正则效果。alpha的合理范围跟数据尺度强相关必须标准化后再调建议用交叉验证在10的负几次方到正几次方之间网格搜索。3. L2范数与Ridge稳定压倒一切3.1 几何视角圆形等值线的“雨露均沾”Ridge的惩罚项等值线是圆高维是球面没有尖角。椭圆和圆相切的位置一般不会正好落在坐标轴上所以Ridge的解几乎不会精确为零而是把所有系数按比例往小压。这个“雨露均沾”的特性意味着Ridge不做特征选择它保留所有特征只是让每个特征的贡献都收敛一些。这个差异在几何上一目了然菱形有棱有角球面圆滑。你要是只记一句话就记“L1有角所以稀疏L2圆滑所以平滑”。3.2 代数视角闭式解与条件数改善Ridge有个漂亮的性质——有闭式解。把目标函数求导令其为零得到w (XᵀX λI)⁻¹Xᵀy。注意那个λI加在对角线上它干了件大事当XᵀX接近奇异特征共线、样本少时加个正数到对角线上能让矩阵可逆数值稳定性大幅提升。这就是为什么Ridge在多重共线性场景下特别靠谱。从条件数角度看λI的加入把最小特征值从可能接近零抬到至少λ条件数被压下来求解更稳。这个原理在信号处理、数值计算里都是通用的不只是回归。3.3 实操Ridge的调参与诊断from sklearn.linear_model import RidgeCV import numpy as np alphas np.logspace(-3, 3, 50) ridge RidgeCV(alphasalphas, cv5) ridge.fit(X_train, y_train) print(f最优alpha: {ridge.alpha_}) print(f测试集R2: {ridge.score(X_test, y_test)}) print(f系数L2范数: {np.linalg.norm(ridge.coef_)})RidgeCV直接帮你做交叉验证选alpha省事。诊断的时候看系数的L2范数随着alpha增大这个值应该单调下降如果没降说明标准化没做好或者alpha范围不对。3.4 注意事项Ridge不是万能的Ridge把所有系数都留着特征多的时候模型解释性差你没法跟业务方说“这三百个特征每个贡献多少”。另外它对异常值敏感因为平方损失本身就会被大残差带偏这时候可以考虑Huber或者先做异常值处理。还有一点Ridge压系数但不归零所以模型体积不会因为正则化而变小部署时该存多少参数还是多少。4. 两者对比与选型什么时候用哪个4.1 一张表看清核心差异维度Lasso (L1)Ridge (L2)惩罚项λΣ|w|λΣw²解的性质稀疏部分系数为零平滑系数整体缩小特征选择会做不做闭式解无需迭代有共线性处理不稳定随机选一个稳定分摊权重高维小样本受样本量限制表现稳健计算复杂度坐标下降较慢矩阵求逆较快这张表建议存下来面试和实战都用得上。核心记忆点要解释性、要筛特征选Lasso要稳定、要抗共线性选Ridge。4.2 弹性网成年人不做选择实际项目里我很少纯用Lasso或Ridge弹性网Elastic Net把两者按比例混起来既保留稀疏性又缓解共线性下的不稳定。它的惩罚项是λ1Σ|w| λ2Σw²两个超参l1_ratio控制混合比例。from sklearn.linear_model import ElasticNetCV enet ElasticNetCV( l1_ratio[0.1, 0.3, 0.5, 0.7, 0.9, 0.95, 1.0], alphasnp.logspace(-3, 2, 30), cv5, max_iter10000 ) enet.fit(X_train, y_train) print(f最优l1_ratio: {enet.l1_ratio_}) print(f最优alpha: {enet.alpha_})l1_ratio接近1就偏向Lasso接近0偏向Ridge。特征成组相关的时候弹性网倾向于把一组相关特征一起保留或一起剔除这个“分组效应”是纯Lasso给不了的。4.3 选型决策树我一般这么判断先看特征数和样本数的关系特征远多于样本优先弹性网或Ridge别指望Lasso全选出来再看特征间相关性相关性高就避开纯Lasso然后看业务是否需要特征筛选清单需要就上Lasso或弹性网最后看数据有没有异常值有的话先清洗再谈正则化。这个顺序不是死的但能帮你少走弯路。5. 实操全流程从数据到模型落地5.1 标准化是前置硬条件正则化对特征尺度极度敏感因为惩罚项是对系数整体施加的如果某个特征量纲大它的系数天然就小惩罚对它的影响和量纲小的特征完全不对等。不标准化直接跑Lasso结果基本没有参考价值。必须用StandardScaler或者自己减均值除标准差而且要在训练集上fit、在测试集上transform别把测试集信息泄漏进来。5.2 交叉验证选超参的完整脚本from sklearn.linear_model import LassoCV, RidgeCV from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler import numpy as np pipe_lasso Pipeline([ (scaler, StandardScaler()), (model, LassoCV(alphasnp.logspace(-4, 1, 50), cv5, max_iter10000)) ]) pipe_lasso.fit(X_train, y_train) print(Lasso最优alpha:, pipe_lasso.named_steps[model].alpha_) pipe_ridge Pipeline([ (scaler, StandardScaler()), (model, RidgeCV(alphasnp.logspace(-3, 3, 50), cv5)) ]) pipe_ridge.fit(X_train, y_train) print(Ridge最优alpha:, pipe_ridge.named_steps[model].alpha_)用Pipeline把标准化和模型绑在一起交叉验证时标准化只在每折的训练部分做避免泄漏。这个细节很多人忽略导致CV分数虚高。5.3 结果解读与业务落地模型跑完别只看R2。Lasso要看非零系数的分布如果非零特征集中在某几个业务维度说明这些维度确实关键如果非零特征散乱且每次CV结果差异大说明数据里噪声多或者特征冗余严重。Ridge要看系数随alpha的变化曲线找那个“再增大alpha性能就明显掉”的拐点。落地时把选出的特征和系数交给业务方配上标准化参数保证线上推理时预处理一致。6. 常见问题排查速查6.1 问题速查表现象可能原因排查方向Lasso系数全为零alpha过大或未标准化缩小alpha检查scalerLasso选的特征每次不同特征高度相关去冗余或换弹性网Ridge系数压不下去alpha过小或尺度问题增大alpha标准化CV分数远高于测试分数数据泄漏检查Pipeline是否隔离训练慢max_iter不足或特征过多增大迭代先做特征筛选6.2 几个踩过的坑有次我跑Lasso非零特征只有三个觉得模型太简单把alpha调小到几乎为零结果过拟合严重。后来才明白稀疏本身不是问题问题是我没验证那三个特征是否真的覆盖了业务逻辑。还有一次Ridge的CV分数很漂亮上线后崩了查了半天发现线上预处理没做标准化系数尺度全乱。这两个教训归结起来就一句正则化模型的成败一半在预处理和验证流程不在模型本身。6.3 独家小技巧调alpha的时候先在对数尺度上粗扫10的负4次方到1次方取20个点找到性能平台区再细扫。看Lasso的系数路径图用lars_path或者自己循环alpha画图能直观看到每个特征是在哪个alpha值被“踢出”的这个图对理解特征重要性排序特别有用。另外如果业务方非要一个“特征重要性排名”Lasso的非零系数绝对值排序比树模型的特征重要性更直接因为它有明确的线性解释。7. 从范数到更远的地方7.1 为什么这个基础值得反复嚼L1和L2这套东西不只用在回归。逻辑回归加L1就是稀疏逻辑回归神经网络里的权重衰减本质就是L2正则甚至推荐系统里的矩阵分解也常加范数约束。你把这两个范数的几何直觉和代数性质吃透换到别的模型上迁移成本极低。我见过太多人调包调得飞起一问为什么L1稀疏就卡壳这种“会用不会想”的状态在遇到新问题时就露馅了。7.2 可以继续深挖的方向想再往深走可以看看次梯度方法怎么处理L1的不可导点坐标下降的收敛性证明还有近端梯度算法proximal gradient怎么统一处理这类复合优化问题。这些偏理论但对理解为什么某些求解器快、某些慢很有帮助。工程侧可以研究一下稀疏矩阵存储和推理加速Lasso产出的稀疏模型在部署时确实能省内存和算力。7.3 一点个人体会我自己的经验是正则化调参最忌讳“一把梭”。先把数据洗干净、标准化做好、用Pipeline隔离流程再谈alpha怎么选。Lasso和Ridge没有绝对优劣只有场景匹配。遇到拿不准的弹性网兜底l1_ratio从0.5开始试多数情况下不会太差。真正拉开差距的不是你用了多花哨的模型而是你对这些基础工具的理解够不够深、用的时候够不够稳。