ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

L1正则化原理详解:从过拟合到稀疏解的手算与实战

L1正则化原理详解:从过拟合到稀疏解的手算与实战 1. 从一个“过拟合”的简单例子说起假设你是一个刚入行的数据分析师老板给了你一个任务根据过去一周的天气数据比如温度、湿度、风速来预测明天的冰淇淋销量。你手头的数据不多只有7天的记录。你决定用一个线性模型来拟合模型形式是销量 w1*温度 w2*湿度 w3*风速 b。为了追求“完美”你可能会想能不能再加一些更复杂的特征比如温度的平方、湿度和风速的乘积甚至把星期几也编码成好几个变量加进去。你一顿操作猛如虎模型在你这7个数据点上预测得分比如R²达到了惊人的0.999几乎完美地穿过了每一个点。你兴冲冲地向老板汇报结果第二天预测完全不准销量暴跌。老板看着你眼神里充满了“友善”的疑问。这就是典型的过拟合。你的模型不仅学到了“温度高销量高”这个普遍规律还强行记住了某天因为促销导致的异常高销量或者某天因为下雨导致的异常低销量。它把数据中的“噪声”和“偶然”也当成了规律来学习。模型变得非常复杂参数w1, w2, w3...的值可能变得很大也很不稳定稍微变动一点数据参数值就剧烈波动。这样的模型在训练集上表现完美但一到未知的新数据测试集或真实世界上就“原形毕露”泛化能力极差。那么如何防止模型变得这么“敏感”和“复杂”呢一个直观的想法是我们能不能在训练时给模型的“复杂程度”加上一个惩罚让模型在拟合数据的同时也尽量保持“简单”。这个“简单”在数学上如何衡量一种常见的方法就是看模型参数权重w的绝对值大小。如果所有参数都很小接近于零那这个模型通常就不会太复杂对输入数据的微小变化也不会反应过度。L1正则项就是实现这种“惩罚”的数学工具之一。它的核心思想是在原来的损失函数比如均方误差后面加上所有权重绝对值之和乘以一个系数。这样模型在努力降低预测误差的同时也会被迫让权重向零收缩。今天我们就用一个极简的、可以手算的例子把L1正则项到底在干什么掰开揉碎了讲清楚。2. L1正则项给模型戴上“紧箍咒”在深入例子之前我们先明确几个基本概念。我们通常说的“训练模型”就是寻找一组参数权重w和偏置b使得模型预测值尽可能接近真实值。衡量这个接近程度的函数叫损失函数比如线性回归里常用的均方误差MSE。没有正则化时我们的目标就是最小化这个损失函数。L1正则化则是在这个目标上增加了一个额外的约束。新的目标函数变成了总损失 原始损失函数 λ * Σ|wi|这里Σ|wi|就是L1正则项它是所有权重通常不包括偏置b的绝对值之和。它衡量了模型的“复杂度”或“规模”。λ读作lambda是一个大于0的超参数叫做正则化强度。它控制着惩罚的力度。λ0就退化成没有正则化的原始问题λ越大对模型复杂度的惩罚就越重模型就越倾向于选择更小的权重。为什么加上这个项就能防止过拟合呢我们可以从两个角度理解约束视角相当于我们在优化原始损失函数时附加了一个条件所有权重的绝对值之和不能太大。这迫使模型不能肆无忌惮地增大权重来“硬凑”训练数据必须在一个有限的“预算”权重绝对值总和内找到最能解释数据的权重分配方案。贝叶斯视角从概率的角度看给损失函数加上L1正则项等价于假设模型的权重参数服从拉普拉斯先验分布。这个分布的特点是它在0处有一个尖峰意味着我们“先验”地认为权重取0的概率比较大。训练过程就是在数据和这个先验信念之间做权衡。L1正则项有一个非常独特且强大的性质它倾向于产生稀疏解。所谓稀疏解就是最终训练出来的模型中很多权重会精确地等于0。这相当于自动帮我们做了特征选择——将那些不重要的、冗余的特征的权重直接置零模型只保留少数关键特征。这与L2正则化权重平方和有本质区别L2正则化只会让权重变小但很少会精确为零。注意λ的选择至关重要。太小了惩罚不够可能还是过拟合太大了惩罚过重模型会变得过于简单可能欠拟合连基本规律都没学好。这通常需要通过交叉验证来确定。3. 手算演示当L1遇到一元线性回归现在我们抛开所有复杂的库和框架用一个最简单的一元线性回归例子来看看L1正则项是如何具体起作用的。这个例子简单到你可以用纸笔跟着算一遍。3.1 问题设定假设我们只有一个特征x要预测目标y。模型是y_pred w * x b。我们有三条训练数据数据点1: (x1, y2)数据点2: (x2, y2.5)数据点3: (x3, y3)我们的目标是找到最优的w和b。3.2 不带正则化的原始问题首先我们看看不加正则项时模型会怎么拟合。我们使用均方误差MSE作为损失函数。Loss_original (1/3) * [(w*1b - 2)² (w*2b - 2.5)² (w*3b - 3)²]为了找到最小化这个Loss的w和b我们可以求偏导数并令其为0对于这个简单问题可以解析求解。通过计算过程略我们可以得到最优解大约为w ≈ 0.5,b ≈ 1.5此时模型为y_pred 0.5*x 1.5。计算一下预测值x1时预测2x2时预测2.5x3时预测3完美拟合所有训练点训练误差为0。这是一个“复杂”的模型吗在这个极简例子中它只是恰好穿过了所有点但权重w0.5并不算大。3.3 加入L1正则项现在我们引入L1正则项并且为了演示稀疏化的效果我们故意把正则化强度λ设得非常大比如λ10。同时为了简化计算并突出L1对权重w的影响我们暂时固定偏置b1.5即采用无正则化时的最优b。这样我们只优化w。新的损失函数为Loss_L1 Loss_original λ * |w|代入b1.5和λ10Loss_L1 (1/3)*[(w*11.5-2)² (w*21.5-2.5)² (w*31.5-3)²] 10*|w|化简Loss_L1 (1/3)*[(w-0.5)² (2w-1)² (3w-1.5)²] 10*|w|进一步化简展开平方项Loss_L1 (1/3)*[(w² - w 0.25) (4w² - 4w 1) (9w² - 9w 2.25)] 10*|w|Loss_L1 (1/3)*[14w² - 14w 3.5] 10*|w|Loss_L1 (14/3)w² - (14/3)w 3.5/3 10*|w|3.4 关键分析绝对值函数带来的“拐点”L1正则项10*|w|在 w0 处是一个“尖点”不可导。因此我们不能简单地用求导等于0的方法来求全局极小值。我们需要分情况讨论w0 和 w0并比较不同区间内的最小值。情况一假设 w 0 那么 |w| w。 此时损失函数为Loss_L1 (14/3)w² - (14/3)w 1.1667 10w (14/3)w² (16/3)w 1.1667这是一个关于w的二次函数开口向上。其最小值在导数等于0处取得d(Loss_L1)/dw (28/3)w 16/3 0w -16/28 -4/7 ≈ -0.571等等我们解出的 w ≈ -0.571但这违反了 w0 的假设。所以在 w0 的区间内这个二次函数是单调递增的因为求出的极值点不在定义域内且导数在w0处为正。因此在w0区间最小值在左端点w0处取得。 代入 w0Loss_L1 0 0 1.1667 1.1667情况二假设 w 0 那么 |w| -w。 此时损失函数为Loss_L1 (14/3)w² - (14/3)w 1.1667 - 10w (14/3)w² - (44/3)w 1.1667求导d(Loss_L1)/dw (28/3)w - 44/3 0w 44/28 11/7 ≈ 1.571解出的 w ≈ 1.571这违反了 w0 的假设。所以在 w0 区间这个二次函数是单调递减的极值点不在定义域内且导数在w0处为负。因此在w0区间函数值随着w减小而增大越往负方向走损失越大。我们关心的是最小值所以要看右端点但w0的区间右端点是无限接近0的负数。我们取一个极限当w从负方向无限接近0时损失函数值无限接近情况一中w0时的值吗注意在w0处函数本身是连续的但导数不连续。我们直接计算一个非常接近0的负数比如 w -0.001Loss_L1 (14/3)*(1e-6) - (44/3)*(-0.001) 1.1667 ≈ 0 0.01467 1.1667 1.1814这比 w0 时的 1.1667 要大。3.5 结论与稀疏性的诞生对比两种情况当 w0 时Loss_L1 1.1667当 w 为负数或正数时损失函数值都大于或等于在w0时1.1667。因此在 λ10 这个巨大的惩罚强度下最优解就是 w 0这意味着什么意味着L1正则项的强大惩罚迫使模型完全放弃了特征x最终的模型退化为y_pred b 1.5即一个常数模型。它预测任何x输出都是1.5。虽然这在训练集上误差变大了从0变成了1.1667但模型变得极其简单权重为0这正是在极端惩罚下防止过拟合的体现——模型宁愿欠拟合也不要一个可能过拟合的复杂模型。这就是稀疏性权重w被精确地压缩到了0。在这个例子中因为λ极大所以稀疏性被极端地展示了。在实际应用中λ会调到一个合适的值它可能会把一些不重要的特征的权重压到0同时保留重要特征的较小非零权重。4. 可视化理解损失函数的“地形图”与“拉力”如果觉得上面的代数推导有点抽象我们可以用更直观的几何方式来理解。想象一个二维平面横轴是权重w纵轴是损失函数的值。原始损失函数Loss_original是一个平滑的、开口向上的抛物线在我们这个简化例子中它的最低点就在我们之前算出的 w≈0.5 的地方。L1正则项10*|w|的图像是一个“V”字形在w0处有一个尖锐的底点。总损失Loss_L1是上面两个图像相加。相加之后原来抛物线的最低点w≈0.5处因为加上了10*0.55的惩罚导致该点被大幅抬高了。而w0处虽然原始损失函数的值不是最低大约1.1667但加上惩罚项10*00后总损失反而比w≈0.5处更小。你可以想象有两个力在拉扯最优的w数据拟合的力来自Loss_original它想把w拉向0.5因为那里对训练数据拟合得最好。正则化的力来自λ*|w|它想把w拉向0因为那里模型最简单。当λ很小比如0.1时数据拟合的力占主导最终w会在0.5附近但比0.5稍微靠近0一点比如0.45。 当λ很大比如我们例子中的10时正则化的力占绝对主导它强行把w拉到了0。L1的“尖角”效应L2正则项w²的图像是一个平滑的碗状它与抛物线相加后最低点会平滑地向原点移动。但L1的“V”字形有个尖角这个尖角与抛物线相加时很容易把最终的总损失最低点“吸引”到这个尖角上即w0点尤其是当抛物线本身在0附近比较平坦的时候。这就是L1能产生精确零解的根本几何原因。5. 从理论到实践L1正则化的应用与调参理解了极简例子背后的原理我们来看看在实际的机器学习项目比如使用Python的Scikit-learn库中如何应用并调优L1正则化。5.1 在Scikit-learn中的应用在Scikit-learn中L1正则化通常被集成在线性模型里。最常见的两个类是Lasso用于线性回归其损失函数就是MSE α * Σ|wi|。这里的α就等价于我们之前说的λ。LogisticRegression(penalty‘l1’)用于逻辑回归同样可以施加L1惩罚。下面是一个简单的代码示例对比有无L1正则化的区别import numpy as np from sklearn.linear_model import LinearRegression, Lasso from sklearn.preprocessing import StandardScaler import matplotlib.pyplot as plt # 生成一些数据故意加入一些噪声和无关特征 np.random.seed(42) n_samples, n_features 50, 10 X np.random.randn(n_samples, n_features) # 10个特征 # 只有前2个特征与目标值真正相关 coef 3 * np.random.randn(n_features) coef[2:] 0 # 将后8个特征的真实权重设为0 y np.dot(X, coef) np.random.randn(n_samples) * 1.5 # 划分训练集和测试集 from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.3, random_state42) # 特征标准化对L1正则化非常重要 scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) # 1. 使用普通线性回归无正则化 lr LinearRegression() lr.fit(X_train_scaled, y_train) print(普通线性回归 - 训练集R², lr.score(X_train_scaled, y_train)) print(普通线性回归 - 测试集R², lr.score(X_test_scaled, y_test)) print(普通线性回归 - 权重绝对值之和, np.sum(np.abs(lr.coef_))) # 2. 使用Lasso回归L1正则化 # 我们需要寻找一个合适的alpha值这里先用一个默认值 lasso Lasso(alpha0.1, max_iter10000) # max_iter调大确保收敛 lasso.fit(X_train_scaled, y_train) print(\nLasso回归 (alpha0.1) - 训练集R², lasso.score(X_train_scaled, y_train)) print(Lasso回归 (alpha0.1) - 测试集R², lasso.score(X_test_scaled, y_test)) print(Lasso回归 (alpha0.1) - 权重绝对值之和, np.sum(np.abs(lasso.coef_))) print(非零权重的数量, np.sum(lasso.coef_ ! 0)) # 查看权重观察稀疏性 print(\n普通线性回归权重, lr.coef_) print(Lasso回归权重, lasso.coef_)运行这段代码你很可能会发现普通线性回归在训练集上R²很高但在测试集上下降明显过拟合迹象且所有特征的权重都不为零。Lasso回归在测试集上的表现可能更好或相当但最关键的是它的权重向量中很多元素变成了0。这正是我们期望的特征选择效果——模型自动识别并剔除了那些不重要的特征。5.2 如何选择关键的超参数 α (λ)alpha是控制L1正则化强度的超参数它的选择至关重要。通常通过交叉验证来完成。from sklearn.linear_model import LassoCV # 使用LassoCV进行交叉验证选择最佳alpha # alphas参数提供一系列候选值通常以对数尺度分布 lasso_cv LassoCV(alphasnp.logspace(-4, 0, 50), cv5, max_iter10000, random_state42) lasso_cv.fit(X_train_scaled, y_train) print(通过交叉验证选择的最佳alpha, lasso_cv.alpha_) print(使用最佳alpha的Lasso模型在测试集上的R², lasso_cv.score(X_test_scaled, y_test)) print(非零权重的数量, np.sum(lasso_cv.coef_ ! 0))LassoCV会尝试你提供的alphas列表对每个alpha进行交叉验证最终选择在交叉验证中平均得分最高的那个alpha。这是实践中确定正则化强度的标准方法。5.3 实操心得与常见坑特征标准化是必须的L1正则化惩罚的是权重的绝对值。如果特征A的取值范围是[0, 1000]特征B的取值范围是[0, 1]那么即使特征B更重要模型也可能为了减小特征A的巨大权重带来的惩罚而牺牲对特征B的拟合。因此在使用L1或任何基于距离/惩罚的模型前必须对特征进行标准化如StandardScaler使其均值为0方差为1处于同一量纲。偏置项Intercept通常不惩罚在绝大多数实现中包括Scikit-learn正则化项只作用于权重coef_而不作用于偏置intercept_。因为偏置项只是平移整个预测函数不影响模型的“复杂度”或特征选择。收敛问题由于L1正则项在零点不可导使用梯度下降求解时可能需要特殊的算法如坐标下降法这也是Scikit-learn中Lasso默认使用的算法。有时需要增加max_iter参数来确保模型收敛。如果看到收敛警告首先尝试增大max_iter。与L2结合弹性网络Elastic Net有时单纯使用L1可能过于激进特别是当特征之间存在高度相关性时L1可能会随机选择其中一个而忽略其他。一种折中的方案是使用弹性网络它同时结合了L1和L2正则化Loss λ1*Σ|wi| λ2*Σwi²。在Scikit-learn中对应ElasticNet类。这通常能产生更好的泛化性能尤其是当特征数远大于样本数或者特征间高度相关时。6. 总结与拓展思考通过这个从极简手算例子到实际代码应用的旅程我们应该对L1正则项有了一个立体而深刻的认识。它不仅仅是一个数学公式里的一项更是一种控制模型复杂度的强大思想工具。它的核心价值在于通过引入稀疏性来实现自动特征选择从而构建出更简单、解释性更强、泛化能力可能更好的模型。回顾一下L1正则化的精髓在于目标在拟合数据和保持模型简洁之间取得平衡防止过拟合。手段在损失函数中加入权重绝对值之和作为惩罚项。结果倾向于产生稀疏权重向量即许多权重精确为零。实现通过调整超参数λ或α来控制惩罚力度通常用交叉验证选择。最后分享一点我个人在特征工程中的体会在数据科学的初期我们总是倾向于尽可能多地收集和构造特征担心遗漏任何可能有用的信息。然而“少即是多”的原则在机器学习中常常成立。L1正则化提供了一种数据驱动的方式来执行这个“做减法”的过程。与其依赖主观判断或复杂的特征选择算法不如让模型在训练过程中自己决定哪些特征是真正重要的。当你看到一个Lasso模型最终只保留了5个非零权重而性能却不降反升时你不仅能得到一个更高效的预测模型还能获得对业务问题更深刻的理解——知道是哪几个关键因素在真正驱动你的预测目标。这种简洁性和可解释性在很多时候比单纯的预测精度提升更有价值。
返回列表