news 2026/10/31 7:38:21

从距离度量到正则化:L1与L2范数的几何、代数与工程实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从距离度量到正则化:L1与L2范数的几何、代数与工程实践

数学基础这个系列我断断续续写了快两年,每次写到范数这一节,评论区就会冒出一堆问题:为什么L1能做出稀疏解而L2不能?为什么Lasso的坐标下降要那么写?距离度量和正则化到底是怎么扯上关系的?说实话,我一开始学的时候也在这块卡了很久,教材上把“范数”和“正则化”分成两章讲,中间那层窗户纸没人帮你捅破,你就总觉得这是两个不相干的东西。这篇就把这层窗户纸彻底撕开,从曼哈顿距离和欧氏距离讲起,一路推到Lasso和Ridge的求解细节、几何直觉、参数选择,以及我在实际项目里踩过的坑。不管你是刚学完线性代数想找个落脚点,还是已经用过sklearn但没搞明白背后在算什么,这篇应该都能让你有收获。

1. 从距离度量到正则项:一条被忽视的逻辑线

1.1 范数到底是什么,为什么它同时出现在两个地方

很多人第一次见到“范数”是在距离公式里,第二次见到是在损失函数后面那个加项里,然后就开始困惑:这俩是同一个东西吗?答案是同一个东西,只是用法不同。范数本质上是一个函数,它把向量映射成一个非负实数,衡量的是这个向量“有多大”。L1范数就是把所有分量的绝对值加起来,L2范数就是把所有分量的平方加起来再开根号。就这么简单。

那为什么它既能当距离又能当惩罚项?关键在于理解“向量之差”这个概念。两个点之间的距离,本质上就是它们坐标向量之差的范数。你算曼哈顿距离,就是算差值向量的L1范数;你算欧氏距离,就是算差值向量的L2范数。而正则化做的事情,是把模型参数向量本身当作一个“点”,惩罚它离原点的距离。所以L1正则就是惩罚参数向量的L1范数,L2正则就是惩罚参数向量的L2范数。距离度量衡量的是“两个样本差多少”,正则化衡量的是“参数离零有多远”,数学形式完全一样,只是作用对象换了。

这个统一视角非常重要,因为后面所有的几何直觉都建立在这上面。你把参数向量想象成空间里的一个点,L1正则的等值线是菱形(二维情况下),L2正则的等值线是圆。损失函数的等值线和这些约束形状相切的位置,就决定了最优解落在哪里。L1的菱形有尖角,尖角正好落在坐标轴上,所以最优解容易出现在某些分量为零的位置,这就是稀疏性的几何来源。L2的圆没有尖角,切点一般不会正好落在坐标轴上,所以参数会被压缩但不会变成零。

提示:如果你只记一句话,就记这个——L1的菱形有角,L2的圆没角,角在坐标轴上,所以L1出稀疏解。这是理解Lasso和Ridge全部差异的钥匙。

1.2 为什么距离的名字叫曼哈顿和欧氏

这两个名字其实挺形象的。曼哈顿距离得名于曼哈顿的街道网格,你从一个路口到另一个路口,只能沿着横平竖直的街道走,不能穿墙,所以走的距离是横向差加纵向差。欧氏距离就是两点之间直线最短,拿尺子量出来的距离。放到高维空间里,这个直觉依然成立:L1范数假设你只能沿着坐标轴方向移动,L2范数允许你走对角线。

这个直觉对理解正则化的行为很有帮助。L1正则像是在说“你只能沿着坐标轴方向调整参数”,所以它倾向于把某些参数直接调到零,然后只在剩下的参数上做调整。L2正则像是在说“你可以沿任意方向调整,但整体别跑太远”,所以它会把所有参数都均匀地压小一点,但很少压到正好为零。我在给团队新人讲这块的时候,就用这个街道网格的比喻,基本没人听不懂。

1.3 从距离到回归:正则化到底在防什么

要理解Lasso和Ridge为什么存在,得先理解它们防的是什么问题。线性回归的最小二乘解是让残差平方和最小,这个解在数据量充足、特征之间不相关的时候表现很好。但现实往往不这么理想:特征之间高度相关(多重共线性),或者特征数比样本数还多(高维小样本),这时候最小二乘解会变得极不稳定,参数的方差会爆炸,模型在新数据上表现很差。这就是过拟合的一种表现形式。

正则化的思路是给损失函数加一个惩罚项,限制参数的大小,从而降低方差、换取一点偏差。这是一笔交易:你牺牲了在训练集上的拟合精度,换来了在测试集上的稳定性。L2正则(Ridge)把参数往零的方向均匀压缩,能有效缓解共线性带来的方差膨胀;L1正则(Lasso)则更进一步,它能把一些参数直接压到零,相当于做了一次自动的特征选择。两者的惩罚力度都由一个超参数控制,通常叫alpha或lambda,这个参数的选择直接决定了正则化的效果,后面会专门讲怎么调。

2. L1与L2的核心差异:几何、代数与概率三条线索

2.1 几何视角:菱形尖角与圆形切点

几何直觉是最直观的入口。把二维参数空间画出来,损失函数的等值线是一圈一圈的椭圆(以最小二乘为例),正则项的等值线是约束形状。优化问题可以理解为:在正则项约束的范围内,找到让损失函数最小的点。这个点就是损失等值线和约束形状的切点。

L1的约束形状是菱形,四个顶点在坐标轴上。当损失椭圆的中心不在坐标轴上时,椭圆往外扩张的过程中,最先碰到的往往是菱形的某个顶点,而顶点意味着其中一个参数为零。这就是L1产生稀疏解的几何解释。L2的约束形状是圆,圆上每个点的“光滑程度”一样,切点落在坐标轴上的概率很低,所以L2解通常所有分量都非零,只是整体被缩小了。

这个解释在二维下很清晰,高维下菱形变成菱形多面体,尖角更多,稀疏性更明显。我建议每个学这块的人都亲手画一次这个图,比看十遍公式都管用。

2.2 代数视角:软阈值与比例收缩

从求解的角度看,两者的差异更具体。对于正交设计矩阵这种简化情形,Lasso的解可以写成软阈值函数的形式:参数估计值等于最小二乘估计值减去一个阈值,如果结果小于零就取零。这个“减去阈值再截断”的操作,就是稀疏性的代数来源——小于阈值的系数直接被清零了。

Ridge的解则是把最小二乘估计值乘以一个小于1的缩放因子,所有系数按比例缩小,但不会变成零。这个差异用一句话概括:Lasso做的是“减法加截断”,Ridge做的是“乘法加缩放”。减法是硬性的,能把小系数直接干掉;乘法是柔性的,只能让系数变小。

这个代数差异也解释了为什么Lasso的求解比Ridge麻烦。Ridge有闭式解,一个矩阵求逆就完事了;Lasso没有闭式解(除非设计矩阵正交),必须用迭代算法,比如坐标下降、近端梯度法或者LARS。这也是为什么早期Ridge比Lasso流行得多,直到坐标下降的高效实现出来,Lasso才真正普及。

2.3 概率视角:高斯先验与拉普拉斯先验

从贝叶斯的角度看,正则化等价于给参数加先验分布。Ridge对应高斯先验,Lasso对应拉普拉斯先验。高斯分布在零附近是光滑的,所以先验把参数往零拉但不会强制为零;拉普拉斯分布在零处有一个尖峰,这个尖峰对应着“参数很可能正好是零”的先验信念,所以后验估计容易产生稀疏解。

这个视角的价值在于,它告诉你正则化不是随便加的,背后有概率模型的解释。你在选择L1还是L2的时候,其实是在选择你对参数分布的假设:你认为参数是稠密的小值(高斯),还是稀疏的、大部分为零(拉普拉斯)。这个假设应该由领域知识来支撑,而不是盲目试。

对比维度L1范数 / LassoL2范数 / Ridge
距离名称曼哈顿距离欧氏距离
约束形状(二维)菱形,顶点在坐标轴圆形,处处光滑
解的特征稀疏,部分系数为零稠密,系数整体缩小
求解方式无闭式解,需迭代有闭式解,矩阵求逆
贝叶斯先验拉普拉斯分布高斯分布
主要用途特征选择、高维稀疏缓解共线性、稳定估计
对异常值较稳健较敏感

3. 实操:用坐标下降手写一个Lasso求解器

3.1 为什么选坐标下降而不是梯度下降

Lasso的目标函数是凸的但不可微(在零点处L1项没有导数),标准梯度下降直接用会有问题。坐标下降的思路是每次只优化一个坐标,固定其他坐标不变,把多维问题拆成一维问题。一维的Lasso子问题有解析解,就是软阈值,所以每一轮更新都很便宜。这个算法收敛性有保证,实现也简单,是工业界Lasso求解的主流方法之一。

我选择手写而不是直接调库,是因为只有自己写一遍,你才会真正理解软阈值是怎么起作用的,也才能在调参出问题时知道该往哪看。下面这段代码是我简化过的版本,去掉了加速和稀疏矩阵优化,保留核心逻辑,方便对照理解。

import numpy as np def soft_threshold(z, gamma): if z > gamma: return z - gamma elif z < -gamma: return z + gamma else: return 0.0 def lasso_coordinate_descent(X, y, alpha, max_iter=1000, tol=1e-6): n_samples, n_features = X.shape w = np.zeros(n_features) residual = y - X @ w col_sq_norms = np.sum(X ** 2, axis=0) for iteration in range(max_iter): w_old = w.copy() for j in range(n_features): # 去掉第j个特征当前的贡献,得到偏残差 residual += X[:, j] * w[j] rho = X[:, j] @ residual z = rho / col_sq_norms[j] w[j] = soft_threshold(z, alpha / col_sq_norms[j]) # 把更新后的贡献加回残差 residual -= X[:, j] * w[j] if np.max(np.abs(w - w_old)) < tol: break return w

3.2 逐行拆解:偏残差与软阈值

这段代码的核心在循环内部那几行。residual维护的是当前参数下的残差向量。对第j个特征做更新时,先把该特征当前的贡献从残差里去掉,得到“偏残差”——也就是假设第j个特征不存在时,模型还差多少。然后用这个偏残差和第j列做内积,得到rho,它衡量的是第j个特征和当前残差的相关性。除以该列的平方范数做归一化,得到z,这就是不考虑正则时第j个系数的最优值。

接下来就是软阈值登场:alpha / col_sq_norms[j]是阈值,如果z的绝对值小于这个阈值,系数直接置零;否则向零的方向收缩相应的量。这个操作就是L1正则产生稀疏性的直接原因。更新完系数后,把新的贡献加回残差,进入下一个特征。

注意:col_sq_norms必须提前算好,不能在循环里重复算,否则复杂度会翻倍。另外,如果某一列的平方范数为零(常数零列),要跳过或者做特殊处理,否则会除零。

3.3 一个可复现的验证实验

光看代码不够,得跑个实验验证行为。我构造一个简单的场景:样本数50,特征数20,其中只有5个特征真正有贡献,其余是噪声。用上面的求解器跑一遍,看系数分布。

np.random.seed(42) n, p = 50, 20 X = np.random.randn(n, p) true_w = np.zeros(p) true_w[:5] = [3.0, -2.0, 1.5, -1.0, 0.8] y = X @ true_w + 0.1 * np.random.randn(n) w_lasso = lasso_coordinate_descent(X, y, alpha=0.1) print("非零系数个数:", np.sum(np.abs(w_lasso) > 1e-8)) print("系数:", np.round(w_lasso, 3))

跑下来你会发现,非零系数个数明显少于20,而且集中在真正有贡献的那几个特征上。把alpha调大,非零个数会进一步减少;调小则逐渐逼近最小二乘解。这个实验我建议每个人都跑一遍,改改alpha看看系数怎么变,比看任何理论解释都直观。

3.4 Ridge的闭式解与对比实验

Ridge就简单多了,直接解一个线性方程组。目标函数对参数求导令其为零,得到w = (X^T X + alpha I)^{-1} X^T y。注意这里通常不对截距做正则,所以实际实现时要么先中心化数据,要么在矩阵里把截距对应的对角元设为零。

def ridge_closed_form(X, y, alpha): n_features = X.shape[1] A = X.T @ X + alpha * np.eye(n_features) return np.linalg.solve(A, X.T @ y)

拿同样的数据跑Ridge,你会看到所有系数都非零,只是整体比最小二乘解小了一圈。把两个结果并排打印出来,Lasso的稀疏和Ridge的稠密对比一目了然。这个对比实验是我每次讲这块必做的,效果比任何PPT都好。

4. 参数选择与工程实践中的坑

4.1 alpha怎么调:交叉验证的正确姿势

alpha是控制正则化强度的关键超参数,调大了欠拟合,调小了过拟合。标准做法是K折交叉验证,在一组候选alpha上分别训练和验证,选验证误差最小的那个。sklearn里的LassoCV和RidgeCV就是干这个的,内部用高效的路径算法一次性算出整条正则化路径上的解,比暴力网格搜索快得多。

但这里有个坑:交叉验证的折数和alpha网格的粒度要匹配。折数太少(比如3折),验证误差的估计方差大,选出来的alpha不稳定;网格太粗,可能错过最优点。我的经验是5折起步,alpha用对数刻度,从1e-4到1e2取50到100个点。另外,如果特征量纲差异大,一定要先标准化,否则惩罚项对不同特征的力度不一样,结果没有意义。

提示:标准化要在交叉验证的每一折内部做,用训练折的均值和方差去变换验证折,不能在全量数据上先标准化再切分,否则会有信息泄露。sklearn的Pipeline可以帮你自动处理这个顺序。

4.2 多重共线性下Lasso的“任性”行为

这是我在实际项目里踩过的最大的坑。当一组特征高度相关时,Lasso倾向于从这组里随便挑一个保留,把其他的压到零,而且挑哪个对数据的微小扰动很敏感。你换个随机种子重新采样,可能挑中的特征就变了。这导致模型的可解释性打折扣——你以为Lasso帮你选出了“重要特征”,其实它只是从一组等价特征里随机挑了一个代表。

Ridge在这种情况下表现更稳定,它会把相关特征的系数分摊,虽然不能做选择,但估计的方差小。所以如果你的目标是预测精度而非特征选择,或者特征之间相关性很强,Ridge往往是更稳妥的选择。如果确实需要稀疏性,可以考虑Elastic Net,它是L1和L2的结合,既能选择又能处理相关性,代价是多一个超参数要调。

4.3 高维小样本场景的注意事项

特征数远大于样本数时(比如基因数据、文本数据),Lasso最多只能选出与样本数相当的个非零特征,这是L1正则的一个理论限制。这时候如果真实的重要特征很多,Lasso会漏掉一部分。应对办法包括:先用其他方法降维再上Lasso,或者用Elastic Net,或者用稳定性选择(多次子采样取交集)来提高选择的可靠性。

另外,高维场景下坐标下降的收敛可能变慢,需要适当增加最大迭代次数。我遇到过迭代没收敛但代码不报错的情况,结果系数还是半成品,排查了半天才发现是max_iter设小了。建议在求解后检查一下是否真的收敛,或者把max_iter设得宽松一些。

常见问题现象排查与解决
系数全为零alpha过大减小alpha,检查特征是否已标准化
结果不稳定特征高度相关改用Ridge或Elastic Net,或做稳定性选择
迭代不收敛高维或共线性强增大max_iter,检查数据标准化
验证误差异常标准化信息泄露用Pipeline在折内标准化
选出的特征不合理Lasso随机挑选相关特征结合领域知识,用稳定性选择交叉验证

4.4 一个容易被忽略的细节:截距的处理

正则化通常只惩罚斜率系数,不惩罚截距。原因很直白:截距反映的是目标变量的整体水平,惩罚它相当于强行把预测往零拉,没有道理。实现时如果直接对所有参数加惩罚,截距会被不必要地压缩,导致模型有偏。sklearn默认fit_intercept=True并且不对截距正则,但如果你自己手写求解器,记得先对数据做中心化处理,或者把截距对应的惩罚系数设为零。这个小细节在教科书里经常一笔带过,但实际写代码时忘了它,结果会差不少。

5. 从范数到模型选择:我的经验判断

5.1 什么时候用Lasso,什么时候用Ridge

这个问题没有标准答案,但有一些实用的判断规则。特征数量大且你相信只有少数特征真正重要时,用Lasso,它的稀疏性帮你做特征选择,模型也更容易解释。特征之间相关性高、或者你更看重预测稳定性时,用Ridge。两者都拿不准时,Elastic Net是安全的折中,代价是多调一个参数。

还有一个维度是样本量。样本量充足时,两者的差异没那么大;样本量小、特征多时,正则化的选择对结果影响显著,这时候交叉验证的可靠性也更值得关注。我个人的习惯是先把Ridge跑一遍作为基线,再试Lasso看稀疏化能带来多少解释性收益,如果收益不明显就留在Ridge。

5.2 范数思维的其他用武之地

L1和L2的这套思维不只用在回归上。L2正则几乎出现在所有神经网络的训练里(weight decay),作用同样是控制模型复杂度。L1正则用在需要稀疏性的场景,比如压缩感知、稀疏编码。甚至距离度量本身也有广泛应用:L1距离在图像匹配、推荐系统的相似度计算里都有用,因为它对异常值不那么敏感;L2距离则是最常用的相似度度量。

理解范数的统一视角,能让你在遇到新问题时快速判断该用哪种。核心判断标准就一条:你需要的是“挑出少数重要的”(L1),还是“整体压小保持稳定”(L2)。这个判断在回归、分类、降维、神经网络里都通用。

5.3 最后分享一个调试小技巧

如果你怀疑正则化没起作用或者起反作用,做一个简单的诊断:把alpha从很小扫到很大,画出训练误差和验证误差随alpha变化的曲线。正常的曲线应该是训练误差单调上升、验证误差先降后升的U形。如果验证误差一直上升,说明你的基线模型已经欠拟合,问题不在正则化;如果训练误差几乎不变,说明alpha的影响被其他因素掩盖了,检查一下特征尺度或者求解器是否收敛。这个曲线我每次调参都会画,五分钟的事,能省掉大量瞎猜的时间。

这套从距离到正则化的逻辑线,我从第一次接触到现在用了好几年,每次回头看都有新的体会。最开始只是记住公式,后来理解了几何,再后来在项目里被共线性坑过、被标准化顺序坑过、被迭代不收敛坑过,才真正把这些知识串起来。数学基础这东西,光看是看不明白的,得动手跑、动手改、动手踩坑,才能变成自己的东西。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/31 7:37:16

SpringBoot+Vue全栈智能家居系统架构设计与实践

1. 智能家居系统架构设计解析2025年的智能家居系统开发已经进入全栈整合时代&#xff0c;SpringBootVue的技术组合成为企业级解决方案的标准配置。这套架构的核心优势在于前后端完全解耦&#xff0c;后端采用SpringBoot提供的RESTful API作为服务支撑&#xff0c;前端通过Vue实…

作者头像 李华
网站建设 2026/10/31 7:36:05

MySQL索引原理、分类与优化实践全解析

1. MySQL索引概述索引是数据库系统中用于加速数据检索的关键数据结构&#xff0c;它类似于书籍的目录&#xff0c;能够帮助数据库引擎快速定位到所需数据。在MySQL中&#xff0c;索引的合理使用可以显著提升查询性能&#xff0c;但不当使用也可能导致性能下降。1.1 索引的基本原…

作者头像 李华
网站建设 2026/10/31 7:35:21

SQL中NULL值处理的常见误区与最佳实践

1. SQL中NULL值处理的常见误区与解决方案在数据库开发中&#xff0c;NULL值的处理是一个看似简单却容易踩坑的领域。最近我在排查一个生产环境问题时&#xff0c;就遇到了"非空但非NULL判断报错"的典型场景。这个问题暴露了SQL中NULL处理的特殊性&#xff0c;以及开发…

作者头像 李华
网站建设 2026/10/31 7:34:52

Kubernetes v1.31.14 集群部署与生产环境配置指南

1. Kubernetes v1.31.14 集群部署概述Kubernetes作为当前容器编排领域的事实标准&#xff0c;其集群部署一直是运维和开发团队的核心技能。v1.31.14作为长期支持版本&#xff08;LTS&#xff09;的一个补丁更新&#xff0c;主要修复了之前版本中发现的关键安全漏洞和稳定性问题…

作者头像 李华
网站建设 2026/10/31 7:34:28

拓扑光子学在太赫兹通信中的仿真与应用

1. 项目概述&#xff1a;拓扑光子学与太赫兹通信的革命性结合在硅基片上操控太赫兹波&#xff0c;听起来像是科幻小说里的情节&#xff0c;但拓扑光子学正在将这个设想变为现实。作为一名长期从事光子器件仿真的工程师&#xff0c;我最近完整复现了基于谷霍尔效应的光子晶体模型…

作者头像 李华
网站建设 2026/10/31 7:34:17

合肥包河区优质酒店推荐与预订攻略

1. 包河区酒店住宿体验概述包河区作为合肥市的核心城区&#xff0c;拥有完善的商业配套和便捷的交通网络&#xff0c;区域内酒店选择丰富多样。从商务出行到休闲旅游&#xff0c;不同类型的旅客都能在这里找到适合自己的住宿选择。近年来随着消费升级&#xff0c;包河区酒店业呈…

作者头像 李华