.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "auto_examples/linear_model/plot_lasso_and_elasticnet.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download_auto_examples_linear_model_plot_lasso_and_elasticnet.py>`
        to download the full example code. or to run this example in your browser via Binder

.. rst-class:: sphx-glr-example-title

.. _sphx_glr_auto_examples_linear_model_plot_lasso_and_elasticnet.py:


==================================
基于L1的稀疏信号模型
==================================

本示例比较了三种基于L1的回归模型在一个由稀疏且相关特征生成的合成信号上的表现,这些信号进一步被加性高斯噪声所破坏:

 - :ref:`lasso` ;
 - :ref:`自动相关性确定` ;
 - :ref:`弹性网络` .

已知当数据维度增加时,Lasso估计值趋近于模型选择估计值,前提是无关变量与相关变量的相关性不太高。在存在相关特征的情况下,Lasso本身无法选择正确的稀疏模式 [1]_。

在这里,我们比较了这三种模型在以下方面的表现::math:`R^2` 得分、拟合时间以及估计系数的稀疏性,并与真实值进行对比。

.. GENERATED FROM PYTHON SOURCE LINES 16-19

.. code-block:: Python


    # Author: Arturo Amor <david-arturo.amor-quiroz@inria.fr>








.. GENERATED FROM PYTHON SOURCE LINES 20-26

生成合成数据集
-----------------

我们生成一个样本数量少于特征总数的数据集。这会导致一个欠定系统,即解不是唯一的,因此我们不能单独应用普通最小二乘法。正则化在目标函数中引入一个惩罚项,这会修改优化问题,并有助于缓解系统的欠定性质。

目标 `y` 是正弦信号的交替符号线性组合。 `X` 中的 100 个频率中只有最低的 10 个被用来生成 `y` ,其余的特征没有信息量。这导致了一个高维稀疏特征空间,其中需要一定程度的 l1 惩罚。

.. GENERATED FROM PYTHON SOURCE LINES 26-43

.. code-block:: Python


    import numpy as np

    rng = np.random.RandomState(0)
    n_samples, n_features, n_informative = 50, 100, 10
    time_step = np.linspace(-2, 2, n_samples)
    freqs = 2 * np.pi * np.sort(rng.rand(n_features)) / 0.01
    X = np.zeros((n_samples, n_features))

    for i in range(n_features):
        X[:, i] = np.sin(freqs[i] * time_step)

    idx = np.arange(n_features)
    true_coef = (-1) ** idx * np.exp(-idx / 10)
    true_coef[n_informative:] = 0  # sparsify coef
    y = np.dot(X, true_coef)








.. GENERATED FROM PYTHON SOURCE LINES 44-45

一些信息特征具有接近的频率,从而引发(反)相关性。

.. GENERATED FROM PYTHON SOURCE LINES 45-49

.. code-block:: Python



    freqs[:n_informative]





.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    array([ 2.9502547 , 11.8059798 , 12.63394388, 12.70359377, 24.62241605,
           37.84077985, 40.30506066, 44.63327171, 54.74495357, 59.02456369])



.. GENERATED FROM PYTHON SOURCE LINES 50-51

使用 :func:`numpy.random.random_sample` 引入随机相位,并向特征和目标添加一些高斯噪声(由 :func:`numpy.random.normal` 实现)。

.. GENERATED FROM PYTHON SOURCE LINES 51-58

.. code-block:: Python


    for i in range(n_features):
        X[:, i] = np.sin(freqs[i] * time_step + 2 * (rng.random_sample() - 0.5))
        X[:, i] += 0.2 * rng.normal(0, 1, n_samples)

    y += 0.2 * rng.normal(0, 1, n_samples)








.. GENERATED FROM PYTHON SOURCE LINES 59-61

例如,从监测某些环境变量的传感器节点可以获得这种稀疏、噪声和相关的特征,因为它们通常根据其位置(空间相关性)记录相似的值。
我们可以可视化目标。

.. GENERATED FROM PYTHON SOURCE LINES 61-69

.. code-block:: Python


    import matplotlib.pyplot as plt

    plt.plot(time_step, y)
    plt.ylabel("target signal")
    plt.xlabel("time")
    _ = plt.title("Superposition of sinusoidal signals")




.. image-sg:: /auto_examples/linear_model/images/sphx_glr_plot_lasso_and_elasticnet_001.png
   :alt: Superposition of sinusoidal signals
   :srcset: /auto_examples/linear_model/images/sphx_glr_plot_lasso_and_elasticnet_001.png
   :class: sphx-glr-single-img





.. GENERATED FROM PYTHON SOURCE LINES 70-71

我们将数据分为训练集和测试集以简化操作。实际上,应该使用 :class:`~sklearn.model_selection.TimeSeriesSplit` 交叉验证来估计测试分数的方差。这里我们设置 `shuffle="False"` ,因为在处理具有时间关系的数据时,不能使用在测试数据之后的训练数据。

.. GENERATED FROM PYTHON SOURCE LINES 71-77

.. code-block:: Python



    from sklearn.model_selection import train_test_split

    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, shuffle=False)








.. GENERATED FROM PYTHON SOURCE LINES 78-84

在下文中,我们计算了三个基于 l1 模型的拟合优度 :math:`R^2` 得分和拟合时间。然后我们绘制了一个图表,将估计系数的稀疏性与真实系数进行比较,最后我们分析了之前的结果。

Lasso
-----

在这个示例中,我们演示了一个具有固定正则化参数 `alpha` 的 :class:`~sklearn.linear_model.Lasso` 。在实际应用中,应该通过将 :class:`~sklearn.model_selection.TimeSeriesSplit` 交叉验证策略传递给 :class:`~sklearn.linear_model.LassoCV` 来选择最优参数 `alpha` 。为了使示例简单且执行速度快,我们在这里直接设置了 alpha 的最优值。

.. GENERATED FROM PYTHON SOURCE LINES 84-97

.. code-block:: Python

    from time import time

    from sklearn.linear_model import Lasso
    from sklearn.metrics import r2_score

    t0 = time()
    lasso = Lasso(alpha=0.14).fit(X_train, y_train)
    print(f"Lasso fit done in {(time() - t0):.3f}s")

    y_pred_lasso = lasso.predict(X_test)
    r2_score_lasso = r2_score(y_test, y_pred_lasso)
    print(f"Lasso r^2 on test data : {r2_score_lasso:.3f}")





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    Lasso fit done in 0.001s
    Lasso r^2 on test data : 0.480




.. GENERATED FROM PYTHON SOURCE LINES 98-102

自动相关性确定 (ARD)
-----------------------

ARD回归是Lasso的贝叶斯版本。如果需要,它可以为所有参数(包括误差方差)生成区间估计。当信号具有高斯噪声时,它是一个合适的选择。请参阅示例 :ref:`sphx_glr_auto_examples_linear_model_plot_ard.py` ,以比较 :class:`~sklearn.linear_model.ARDRegression` 和 :class:`~sklearn.linear_model.BayesianRidge` 回归器。

.. GENERATED FROM PYTHON SOURCE LINES 102-113

.. code-block:: Python


    from sklearn.linear_model import ARDRegression

    t0 = time()
    ard = ARDRegression().fit(X_train, y_train)
    print(f"ARD fit done in {(time() - t0):.3f}s")

    y_pred_ard = ard.predict(X_test)
    r2_score_ard = r2_score(y_test, y_pred_ard)
    print(f"ARD r^2 on test data : {r2_score_ard:.3f}")





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    ARD fit done in 0.018s
    ARD r^2 on test data : 0.543




.. GENERATED FROM PYTHON SOURCE LINES 114-120

ElasticNet
----------

:class:`~sklearn.linear_model.ElasticNet` 是 :class:`~sklearn.linear_model.Lasso` 和 :class:`~sklearn.linear_model.Ridge` 之间的中间地带,因为它结合了 L1 和 L2 惩罚。正则化的程度由两个超参数 `l1_ratio` 和 `alpha` 控制。当 `l1_ratio = 0` 时,惩罚是纯 L2,模型等同于 :class:`~sklearn.linear_model.Ridge` 。类似地, `l1_ratio = 1` 是纯 L1 惩罚,模型等同于 :class:`~sklearn.linear_model.Lasso` 。对于 `0 < l1_ratio < 1` ,惩罚是 L1 和 L2 的组合。

正如之前所做的,我们使用固定的 `alpha` 和 `l1_ratio` 值来训练模型。为了选择它们的最优值,我们使用了 :class:`~sklearn.linear_model.ElasticNetCV` ,这里没有展示以保持示例的简洁。

.. GENERATED FROM PYTHON SOURCE LINES 120-131

.. code-block:: Python


    from sklearn.linear_model import ElasticNet

    t0 = time()
    enet = ElasticNet(alpha=0.08, l1_ratio=0.5).fit(X_train, y_train)
    print(f"ElasticNet fit done in {(time() - t0):.3f}s")

    y_pred_enet = enet.predict(X_test)
    r2_score_enet = r2_score(y_test, y_pred_enet)
    print(f"ElasticNet r^2 on test data : {r2_score_enet:.3f}")





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    ElasticNet fit done in 0.001s
    ElasticNet r^2 on test data : 0.636




.. GENERATED FROM PYTHON SOURCE LINES 132-136

结果的绘图和分析
--------------------------------

在本节中,我们使用热图来可视化各线性模型的真实和估计系数的稀疏性。

.. GENERATED FROM PYTHON SOURCE LINES 136-167

.. code-block:: Python


    import matplotlib.pyplot as plt
    import pandas as pd
    import seaborn as sns
    from matplotlib.colors import SymLogNorm

    df = pd.DataFrame(
        {
            "True coefficients": true_coef,
            "Lasso": lasso.coef_,
            "ARDRegression": ard.coef_,
            "ElasticNet": enet.coef_,
        }
    )

    plt.figure(figsize=(10, 6))
    ax = sns.heatmap(
        df.T,
        norm=SymLogNorm(linthresh=10e-4, vmin=-1, vmax=1),
        cbar_kws={"label": "coefficients' values"},
        cmap="seismic_r",
    )
    plt.ylabel("linear model")
    plt.xlabel("coefficients")
    plt.title(
        f"Models' coefficients\nLasso $R^2$: {r2_score_lasso:.3f}, "
        f"ARD $R^2$: {r2_score_ard:.3f}, "
        f"ElasticNet $R^2$: {r2_score_enet:.3f}"
    )
    plt.tight_layout()




.. image-sg:: /auto_examples/linear_model/images/sphx_glr_plot_lasso_and_elasticnet_002.png
   :alt: Models' coefficients Lasso $R^2$: 0.480, ARD $R^2$: 0.543, ElasticNet $R^2$: 0.636
   :srcset: /auto_examples/linear_model/images/sphx_glr_plot_lasso_and_elasticnet_002.png
   :class: sphx-glr-single-img





.. GENERATED FROM PYTHON SOURCE LINES 168-183

在当前示例中,:class:`~sklearn.linear_model.ElasticNet` 得到了最佳分数并捕捉到了大部分预测特征,但仍未能找到所有的真实成分。请注意,:class:`~sklearn.linear_model.ElasticNet` 和 :class:`~sklearn.linear_model.ARDRegression` 生成的模型比 :class:`~sklearn.linear_model.Lasso` 更不稀疏。

结论
-----------

:class:`~sklearn.linear_model.Lasso` 被认为能够有效地恢复稀疏数据,但在处理高度相关的特征时表现不佳。实际上,如果多个相关特征对目标有贡献,:class:`~sklearn.linear_model.Lasso` 最终只会选择其中一个。在稀疏但不相关的特征情况下,:class:`~sklearn.linear_model.Lasso` 模型会更合适。

:class:`~sklearn.linear_model.ElasticNet` 在系数上引入了一些稀疏性,并将它们的值缩小到零。因此,在存在对目标有贡献的相关特征的情况下,模型仍然能够减少它们的权重,而不将它们完全设为零。这导致模型比纯粹的 :class:`~sklearn.linear_model.Lasso` 更不稀疏,并且可能捕捉到非预测性特征。

:class:`~sklearn.linear_model.ARDRegression` 在处理高斯噪声时表现更好,但仍然无法处理相关特征,并且由于需要拟合先验分布,耗时较长。

References
----------

.. [1] :doi:`"高维数据稀疏表示的Lasso型恢复" N. Meinshausen, B. Yu - 统计年鉴 2009, 第37卷, 第1期, 246-270 <10.1214/07-AOS582>` 


.. rst-class:: sphx-glr-timing

   **Total running time of the script:** (0 minutes 0.230 seconds)


.. _sphx_glr_download_auto_examples_linear_model_plot_lasso_and_elasticnet.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: binder-badge

      .. image:: images/binder_badge_logo.svg
        :target: https://mybinder.org/v2/gh/scikit-learn/scikit-learn/main?urlpath=lab/tree/notebooks/auto_examples/linear_model/plot_lasso_and_elasticnet.ipynb
        :alt: Launch binder
        :width: 150 px

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: plot_lasso_and_elasticnet.ipynb <plot_lasso_and_elasticnet.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: plot_lasso_and_elasticnet.py <plot_lasso_and_elasticnet.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: plot_lasso_and_elasticnet.zip <plot_lasso_and_elasticnet.zip>`


.. include:: plot_lasso_and_elasticnet.recommendations


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_