机器学习初学者 前天 13:52
【机器学习】通透!L1和L2核心区别 !!
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入浅出地介绍了机器学习中常用的正则化方法,包括L1正则化(Lasso)、L2正则化(Ridge)以及它们的结合——Elastic Net。文章解释了这些方法如何通过“惩罚”模型复杂度来防止过拟合,并详细阐述了它们在特征选择、处理高维数据和多重共线性方面的优势。通过代码示例和图表,直观展示了不同正则化方法的效果差异,帮助读者理解其在实际应用中的价值。

💡L1正则化(Lasso)通过将某些特征的系数变为0,实现特征选择,有助于简化模型并提高解释性,尤其适用于特征稀疏的场景。

💡L2正则化(Ridge)通过使所有特征的系数都变小,防止模型过拟合,特别是在存在多重共线性时,能使模型更稳定。

💡Elastic Net结合了L1和L2正则化的优点,既能进行特征选择,又能处理多重共线性问题,适用于高维数据和特征间高度相关的场景。

💡正则化通过在损失函数中添加惩罚项,限制模型参数的自由度,从而提高模型的泛化能力,防止模型在训练集上表现好,但在新数据上表现差的情况。

cos大壮 2025-06-11 11:30 浙江

    L1 和 L2 是啥?

    当我们用模型(比如线性回归)去拟合数据时,如果特征太多、数据太少,模型可能会过拟合

    L1 和 L2 正则化就是在模型训练时“加个惩罚”,防止模型学得太复杂。

    名称

    比喻

    本质

    L1 正则化

    像“懒人整理行李”:宁愿丢掉不重要的东西

    让一些系数变成 0(特征选择)

    L2 正则化

    像“压缩行李”:每样东西都压缩点

    让所有系数都变小(防止过拟合)

      L1 会让一些特征的系数变成 0 → 达到选择特征的效果

      L2 会让所有特征的系数都缩小,但一般不会变成 0 → 所有特征都参与建模,但影响力不同。

    Elastic Net 是啥?

    Elastic Net 就是结合了 L1 和 L2 的“混合正则化”

    它既有 L1 的特征选择能力,又有 L2 的稳定性,特别适合下面这种情况:

    高维数据(特征比样本还多)+ 特征之间高度相关(多重共线性)

    原理详解

    我们先从普通的线性回归说起:

    加上正则项

    L2 正则化(岭回归 Ridge):

    加入 L2 惩罚项(平方和):

      优点:解决共线性,解有闭式解,数值稳定。

      缺点:不能做特征选择(系数不会为 0)。

    L1 正则化(Lasso):

    加入 L1 惩罚项(绝对值和):

      优点:可将某些系数压成 0,实现变量选择。

      缺点:当特征数 >> 样本数 或 多重共线性严重时不稳定。

    Elastic Net:L1 + L2 的加权组合

    Elastic Net 把两种正则化结合起来:

    也常写为如下形式(α 是调节比例):

       ,就是纯 Lasso;

       ,就是纯 Ridge;

      其他情况则是弹性网络(Elastic Net)

    为什么适合「高维 + 多重共线性」

    高维:特征比样本还多(p >> n)

      L2 正则化仍可解,但不能变量选择。

      L1 会随机选取其中一部分非零变量 → 不稳定。

      Elastic Net 在这种场景下能选多个共线特征,而非像 L1 那样“二选一”。

    多重共线性:变量之间高度相关

      Ridge(L2)会平衡多个高度相关的变量,使它们的系数都变小。

      Lasso(L1)会偏向选择其中一个 → 结果不稳定。

      Elastic Net 会成组选择相关特征(grouping effect),更稳定更可靠。

    正则项、过拟合与泛化能力的关系

    1. 什么是过拟合 & 泛化?

    过拟合(Overfitting):模型在训练集上表现很好,但在新数据(测试集)上表现很差,说明它“记住”了训练集而不是“学到”规律。

    泛化能力:模型对未见数据的预测能力。越强越好。

    2. 为什么会过拟合?

    通常由于下面几种原因:

      模型太复杂(比如参数太多、自由度太高)

      特征太多,样本太少(高维问题)

      特征相关性强(多重共线性)

    3. 正则化的作用

    正则项 = 给模型加一个“复杂度惩罚”,限制参数自由度,从而提升泛化能力。

    我们来看两种正则化的作用:

    L2 正则化(Ridge):

      惩罚项:

      意思:不让参数变得太大,每个系数都要“温和”。

      作用:防止模型参数无限增长(过拟合),尤其在特征多、共线时能稳定解。

      泛化能力:平滑泛化,不裁剪变量

    L1 正则化(Lasso):

      惩罚项:

      意思:强制让某些系数变成 0,相当于删除无关特征。

      作用:自动变量选择,提高模型解释性。

      泛化能力:适合稀疏场景,但在特征高度相关时不稳定。

    Elastic Net 的泛化优势

    Elastic Net 的惩罚:

      L2 部分:让模型更稳定(缓解共线性)

      L1 部分:让模型更稀疏(自动特征选择)

      综合效果:提高泛化能力,尤其适用于高维共线性问题。

    从优化角度理解:L1 会导致非光滑问题

    这个部分偏数学,但很关键,尤其有同学想深入理解算法实现(比如坐标下降、子梯度法等)。

    优化中的“光滑”与“非光滑”函数

    光滑函数:梯度是连续的,比如 L2:

    非光滑函数:某点处不可导,比如 L1:   处不可导

    举个例子:

    为什么    处没有导数,只有次梯度(subgradient)

    可视化来看, 在原点处是个尖角,而  是平滑曲线。

    为什么 L1 带来优化难度?

    L1 惩罚使得目标函数不再是光滑凸函数,而是非光滑凸函数

    不能用标准的梯度下降(因为梯度不存在于某些点)

    需要用专门的优化算法,如:

      坐标下降

      LARS-Lasso

      子梯度下降法

      近端梯度法

    L2 正则的优势在于:光滑易优化

     是平滑函数,容易求导 → 优化路径稳定

    常用于大规模机器学习中的 batch 或 SGD(随机梯度下降)

    对比总结:从泛化能力 & 优化角度看 L1 vs L2

    特性

    L1 正则(Lasso)

    L2 正则(Ridge)

    Elastic Net

    惩罚函数形式

    $\sum_j

    \beta_j

    $

    导数性质

    非光滑(不可导于0点)

    光滑(可导)

    部分光滑

    优化难度

    是否能稀疏建模

    不能

    部分能

    是否能缓解共线性

    不稳定

    效果更佳

    泛化能力

    代码说明

    图像 1:Lasso 正则路径图

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    from sklearn.linear_model import Lasso, Ridge, ElasticNet
    from sklearn.model_selection import train_test_split
    from sklearn.preprocessing import StandardScaler
    from sklearn.metrics import mean_squared_error
    from sklearn.linear_model import lars_path

    np.random.seed(42)

    # 数据集
    n_samples, n_features = 10050
    X = np.random.randn(n_samples, n_features)

    # 构造稀疏的真实系数 beta(只有前 5 个非零)
    true_beta = np.zeros(n_features)
    true_beta[:5] = [5-4302]
    y = X @ true_beta + np.random.randn(n_samples) * 0.5# 加入噪声

    # 标准化
    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.2, random_state=42)

    # 模型训练
    lasso = Lasso(alpha=0.1).fit(X_train, y_train)
    ridge = Ridge(alpha=1.0).fit(X_train, y_train)
    enet = ElasticNet(alpha=0.1, l1_ratio=0.5).fit(X_train, y_train)

    # 预测
    lasso_pred = lasso.predict(X_test)
    ridge_pred = ridge.predict(X_test)
    enet_pred = enet.predict(X_test)

    # 均方误差
    lasso_mse = mean_squared_error(y_test, lasso_pred)
    ridge_mse = mean_squared_error(y_test, ridge_pred)
    enet_mse = mean_squared_error(y_test, enet_pred)

    # 正则路径图:LARS 方法(用于 Lasso 路径图)
    alphas_lasso, _, coefs_lasso = lars_path(X_scaled, y, method='lasso', verbose=True)

    # 图像 1: Lasso 正则路径图
    plt.figure(figsize=(106))
    colors = plt.cm.tab20(np.linspace(01, n_features))
    for i in range(n_features):
        plt.plot(-np.log10(alphas_lasso), coefs_lasso[i], label=f'Feature {i+1}', color=colors[i])
    plt.xlabel(r'$-\log_{10}(\alpha)$')
    plt.ylabel('Coefficient value')
    plt.title('Lasso 正则路径图(正则化程度 vs 系数变化)')
    plt.legend(bbox_to_anchor=(1.051), loc='upper left', ncol=2)
    plt.tight_layout()
    plt.grid(True)
    plt.show()

    横轴,表示正则强度从强(左)到弱(右)

    纵轴:每个特征的系数数值

    每一条曲线:一个特征系数在正则化路径上的变化

    这里想要表达的是:

        较大时,Lasso 将大多数系数压缩为 0,只保留最有影响力的几个变量。

      系数逐渐被引入模型:从0跳跃到非零(稀疏性特性)

      说明:Lasso 具有变量选择能力,有助于解释模型,尤其在高维数据中很实用。

    图像 2:Lasso / Ridge / ElasticNet 系数对比条形图(前 20 特征)

    coef_df = pd.DataFrame({
        'Feature': [f'Feature {i+1}'for i in range(n_features)],
        'True Coef': true_beta,
        'Lasso Coef': lasso.coef_,
        'Ridge Coef': ridge.coef_,
        'ElasticNet Coef': enet.coef_
    })

    # 取前20个特征绘图,颜色鲜艳
    top_n = 20
    colors = plt.cm.get_cmap('tab10'4)

    fig, ax = plt.subplots(figsize=(147))
    index = np.arange(top_n)
    bar_width = 0.2

    plt.bar(index, coef_df['True Coef'][:top_n], bar_width, color=colors(0), label='True Coef')
    plt.bar(index + bar_width, coef_df['Lasso Coef'][:top_n], bar_width, color=colors(1), label='Lasso')
    plt.bar(index + 2 * bar_width, coef_df['Ridge Coef'][:top_n], bar_width, color=colors(2), label='Ridge')
    plt.bar(index + 3 * bar_width, coef_df['ElasticNet Coef'][:top_n], bar_width, color=colors(3), label='ElasticNet')

    plt.xlabel('特征编号')
    plt.ylabel('系数值')
    plt.title('图像 2:不同模型下前 20 个特征系数对比')
    plt.xticks(index + bar_width * 1.5, [f'F{i+1}'for i in range(top_n)], rotation=45)
    plt.legend()
    plt.tight_layout()
    plt.grid(True, linestyle='--', alpha=0.5)
    plt.show()

    横轴是前 20 个特征编号(F1 ~ F20)

    每一组颜色代表一种模型估计的系数

      蓝色:真实系数

      橙色:Lasso

      绿色:Ridge

      紫色:ElasticNet

    咱们可以直观看出哪个模型更接近真实参数,可以看到:

      Lasso 由于 L1 正则化,许多系数变成 0,便于解释模型,效果稀疏明显。

      Ridge 不会将系数压缩为 0,但分布更加平滑,有助于处理多重共线性。

      ElasticNet 在两者之间,既可以稀疏又能避免某些变量完全丢失,兼顾平稳性与解释性。

      Lasso 与 ElasticNet 对于稀疏数据建模尤其有效,Ridge 更适合非稀疏但有共线性的场景。

    图像 3:三种模型的预测误差对比(MSE 越低越好)

    mse_values = {
        'Lasso': lasso_mse,
        'Ridge': ridge_mse,
        'ElasticNet': enet_mse
    }

    fig, ax = plt.subplots(figsize=(85))
    bars = ax.bar(mse_values.keys(), mse_values.values(), color=['orange''green''purple'])

    # 加入标签
    for bar in bars:
        yval = bar.get_height()
        ax.text(bar.get_x() + bar.get_width() / 2, yval + 0.02f'{yval:.3f}', ha='center', va='bottom', fontsize=12)

    plt.ylabel('Mean Squared Error')
    plt.title('图像 3:Lasso / Ridge / ElasticNet 预测误差比较(越低越好)')
    plt.grid(True, axis='y', linestyle='--', alpha=0.5)
    plt.tight_layout()
    plt.show()

      展示了 Lasso、Ridge 和 ElasticNet 在测试集上的预测误差(均方误差 MSE)

      柱状图顶部显示了具体的误差值,便于对比

    这样,我们便于判断:

      预测误差衡量模型的泛化能力(过拟合 or 欠拟合)

      Ridge 模型在本例中表现最稳健,因其避免过度稀疏,保留更多信息

      Lasso 更倾向于“选择少数变量”,有时在高维稀疏情况下更有优势

      ElasticNet 在两者之间,通常能在多重共线性和稀疏之间找到平衡,表现也很稳健

    图四:ElasticNet 中 

    l1_ratio

     从 0 到 1 的变化对稀疏程度和系数的影响(热力图或线图)

    l1_ratios = np.linspace(0111)
    nonzero_counts = []

    for ratio in l1_ratios:
        model = ElasticNet(alpha=0.1, l1_ratio=ratio, max_iter=10000)
        model.fit(X_train, y_train)
        nonzero_count = np.sum(model.coef_ != 0)
        nonzero_counts.append(nonzero_count)

    # 画图
    fig, ax = plt.subplots(figsize=(106))
    plt.plot(l1_ratios, nonzero_counts, marker='o', linewidth=2, color='crimson')
    plt.xlabel('l1_ratio')
    plt.ylabel('Number of Non-zero Coefficients')
    plt.title('图像 4:ElasticNet 在不同 l1_ratio 下的稀疏性变化(非零系数数量)')
    plt.grid(True)
    plt.xticks(l1_ratios)
    plt.tight_layout()
    plt.show()

    横轴(x-axis):ElasticNet 中的 

    l1_ratio

    ,范围从 0 到 1。

      l1_ratio = 0

      :完全是 Ridge(只用 L2 正则)

      l1_ratio = 1

      :完全是 Lasso(只用 L1 正则)

      之间的值表示 L1 和 L2 的加权组合

    纵轴(y-axis):模型最终拟合出的系数中,非零系数的数量

      即模型保留了多少个特征(变量)

     

    l1_ratio

     趋近于 1,即 Lasso 权重增大,模型会更“激进”地将不重要的特征系数压缩为 0。

    越靠近 Lasso,模型越稀疏,保留的变量越少,提升可解释性。

    Ridge 会收缩系数,但通常不会将它们变成 0,所以在 

    l1_ratio = 0

     时,非零系数数量 ≈ 特征总数
    ElasticNet 的强大之处在于:可调控地折中稀疏性与稳定性

    l1_ratio

     提供了从“全选变量”到“严选变量”的连续控制器。


    阅读原文

    跳转微信打开

    Fish AI Reader

    Fish AI Reader

    AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

    FishAI

    FishAI

    鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

    联系邮箱 441953276@qq.com

    相关标签

    正则化 L1正则化 L2正则化 Elastic Net
    相关文章