模型正则化对训练误差和测试误差的影响#

在此示例中,我们评估线性模型(称为ElasticNet)中正则化参数的影响。为了进行此评估,我们使用ValidationCurveDisplay绘制验证曲线。该曲线显示了模型在不同正则化参数值下的训练分数和测试分数。

确定最佳正则化参数后,我们将比较模型的真实系数和估计系数,以确定模型是否能够从噪声输入数据中恢复系数。

# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause

生成样本数据#

我们生成一个回归数据集,其中特征数量相对于样本数量较多。但是,只有10%的特征是有信息的。在这种情况下,通常使用具有L1惩罚的线性模型来恢复稀疏的系数集。

from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split

n_samples_train, n_samples_test, n_features = 150, 300, 500
X, y, true_coef = make_regression(
    n_samples=n_samples_train + n_samples_test,
    n_features=n_features,
    n_informative=50,
    shuffle=False,
    noise=1.0,
    coef=True,
    random_state=42,
)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, train_size=n_samples_train, test_size=n_samples_test, shuffle=False
)

模型定义#

这里,我们不使用仅包含L1惩罚的模型。相反,我们使用一个ElasticNet模型,它同时包含L1和L2惩罚。

我们固定l1_ratio参数,以便模型找到的解仍然是稀疏的。因此,这种类型的模型试图找到一个稀疏解,但同时又试图将所有系数缩小到零。

此外,我们强制模型的系数为正,因为我们知道make_regression生成具有正信号的响应。因此,我们利用这个先验知识来获得更好的模型。

from sklearn.linear_model import ElasticNet

enet = ElasticNet(l1_ratio=0.9, positive=True, max_iter=10_000)

评估正则化参数的影响#

为了评估正则化参数的影响,我们使用验证曲线。该曲线显示了模型在不同正则化参数值下的训练分数和测试分数。

正则化alpha是应用于模型系数的参数:当它趋于零时,不应用正则化,模型试图以最小的误差拟合训练数据。但是,当特征有噪声时,这会导致过拟合。当alpha增加时,模型系数受到约束,因此模型不能紧密拟合训练数据,从而避免过拟合。但是,如果应用过多的正则化,模型就会欠拟合数据,无法正确捕获信号。

验证曲线有助于找到两种极端情况之间的良好权衡:模型未被正则化,因此足够灵活以拟合信号,但又不至于过于灵活而导致过拟合。ValidationCurveDisplay允许我们显示一系列alpha值下的训练分数和验证分数。

import numpy as np

from sklearn.model_selection import ValidationCurveDisplay

alphas = np.logspace(-5, 1, 60)
disp = ValidationCurveDisplay.from_estimator(
    enet,
    X_train,
    y_train,
    param_name="alpha",
    param_range=alphas,
    scoring="r2",
    n_jobs=2,
    score_type="both",
)
disp.ax_.set(
    title=r"Validation Curve for ElasticNet (R$^2$ Score)",
    xlabel=r"alpha (regularization strength)",
    ylabel="R$^2$ Score",
)

test_scores_mean = disp.test_scores.mean(axis=1)
idx_avg_max_test_score = np.argmax(test_scores_mean)
disp.ax_.vlines(
    alphas[idx_avg_max_test_score],
    disp.ax_.get_ylim()[0],
    test_scores_mean[idx_avg_max_test_score],
    color="k",
    linewidth=2,
    linestyle="--",
    label=f"Optimum on test\n$\\alpha$ = {alphas[idx_avg_max_test_score]:.2e}",
)
_ = disp.ax_.legend(loc="lower right")
Validation Curve for ElasticNet (R$^2$ Score)

为了找到最佳正则化参数,我们可以选择使验证分数最大化的alpha值。

系数比较#

现在我们已经确定了最佳正则化参数,我们可以比较真实系数和估计系数。

首先,让我们将正则化参数设置为最佳值,并在训练数据上拟合模型。此外,我们将显示此模型的测试分数。

enet.set_params(alpha=alphas[idx_avg_max_test_score]).fit(X_train, y_train)
print(
    f"Test score: {enet.score(X_test, y_test):.3f}",
)
Test score: 0.884

现在,我们绘制真实系数和估计系数。

import matplotlib.pyplot as plt

fig, axs = plt.subplots(ncols=2, figsize=(12, 6), sharex=True, sharey=True)
for ax, coef, title in zip(axs, [true_coef, enet.coef_], ["True", "Model"]):
    ax.stem(coef)
    ax.set(
        title=f"{title} Coefficients",
        xlabel="Feature Index",
        ylabel="Coefficient Value",
    )
fig.suptitle(
    "Comparison of the coefficients of the true generative model and \n"
    "the estimated elastic net coefficients"
)

plt.show()
Comparison of the coefficients of the true generative model and  the estimated elastic net coefficients, True Coefficients, Model Coefficients

虽然原始系数是稀疏的,但估计系数并不那么稀疏。原因是我们已将l1_ratio参数固定为0.9。我们可以通过增加l1_ratio参数来强制模型获得更稀疏的解。

但是,我们观察到,对于在真实生成模型中接近于零的估计系数,我们的模型将它们缩小到零。因此,我们没有恢复真实的系数,但我们得到了与测试集上获得的性能一致的合理结果。

脚本总运行时间:(0分钟4.820秒)

相关示例

Ridge 系数作为 L2 正则化的函数

Ridge 系数作为 L2 正则化的函数

绘制 Ridge 系数作为正则化的函数

绘制 Ridge 系数作为正则化的函数

基于 L1 的稀疏信号模型

基于 L1 的稀疏信号模型

L1 逻辑回归的正则化路径

L1 逻辑回归的正则化路径

由Sphinx-Gallery生成的图库