支持向量机的正则化参数缩放

Beginner

This tutorial is from open-source community. Access the source code

简介

本实验展示了在使用支持向量机(SVM)进行分类时缩放正则化参数的效果。在 SVM 分类中,我们关注以下方程的风险最小化:

C \sum_{i=1, n} \mathcal{L} (f(x_i), y_i) + \Omega (w)

其中:

  • C 用于设置正则化的程度
  • L 是我们的样本和模型参数的损失函数
  • Ω 是我们的模型参数的惩罚函数

虚拟机提示

虚拟机启动完成后,点击左上角切换到“笔记本”标签,以访问 Jupyter Notebook 进行练习。

有时,你可能需要等待几秒钟让 Jupyter Notebook 完成加载。由于 Jupyter Notebook 的限制,操作验证无法自动化。

如果你在学习过程中遇到问题,请随时向 Labby 提问。课程结束后提供反馈,我们将立即为你解决问题。

导入库并生成合成数据集

我们首先导入必要的库,并生成一个适用于 L1 和 L2 正则化的合成数据集。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.svm import LinearSVC
from sklearn.model_selection import validation_curve, ShuffleSplit

n_samples, n_features = 100, 300
X, y = make_classification(n_samples=n_samples, n_features=n_features, n_informative=5, random_state=1)

rng = np.random.RandomState(1)
y = np.sign(0.5 - rng.rand(n_samples))
X = rng.randn(n_samples, n_features // 5) + y[:, np.newaxis]
X += 5 * rng.randn(n_samples, n_features // 5)

L1 惩罚情况

在 L1 惩罚的情况下,理论表明,通过缩放 C,在找到正确的非零参数集及其符号方面,可以实现模型一致性。我们使用一个稀疏的合成数据集来演示这种效果,这意味着只有少数特征对模型来说是有信息价值且有用的。

model_l1 = LinearSVC(penalty="l1", loss="squared_hinge", dual=False, tol=1e-3)

Cs = np.logspace(-2.3, -1.3, 10)
train_sizes = np.linspace(0.3, 0.7, 3)
labels = [f"fraction: {train_size}" for train_size in train_sizes]

results = {"C": Cs}
for label, train_size in zip(labels, train_sizes):
    cv = ShuffleSplit(train_size=train_size, test_size=0.3, n_splits=50, random_state=1)
    train_scores, test_scores = validation_curve(
        model_l1, X, y, param_name="C", param_range=Cs, cv=cv
    )
    results[label] = test_scores.mean(axis=1)
results = pd.DataFrame(results)

fig, axes = plt.subplots(nrows=1, ncols=2, sharey=True, figsize=(12, 6))

## 绘制未缩放 C 时的结果
results.plot(x="C", ax=axes[0], logx=True)
axes[0].set_ylabel("CV 分数")
axes[0].set_title("未缩放")

## 绘制缩放 C 后的结果
for train_size_idx, label in enumerate(labels):
    results_scaled = results[[label]].assign(
        C_scaled=Cs * float(n_samples * train_sizes[train_size_idx])
    )
    results_scaled.plot(x="C_scaled", ax=axes[1], logx=True, label=label)
axes[1].set_title("将 C 按 1 / n_samples 缩放")

_ = fig.suptitle("L1 惩罚下缩放 C 的效果")

L2 惩罚情况

我们可以对 l2 惩罚重复类似的实验。在这种情况下,理论表明,为了实现预测一致性,随着样本数量的增加,惩罚参数应保持不变。

model_l2 = LinearSVC(penalty="l2", loss="squared_hinge", dual=True)
Cs = np.logspace(-4.5, -2, 10)

labels = [f"fraction: {train_size}" for train_size in train_sizes]
results = {"C": Cs}
for label, train_size in zip(labels, train_sizes):
    cv = ShuffleSplit(train_size=train_size, test_size=0.3, n_splits=50, random_state=1)
    train_scores, test_scores = validation_curve(
        model_l2, X, y, param_name="C", param_range=Cs, cv=cv
    )
    results[label] = test_scores.mean(axis=1)
results = pd.DataFrame(results)

fig, axes = plt.subplots(nrows=1, ncols=2, sharey=True, figsize=(12, 6))

## 绘制未缩放 C 时的结果
results.plot(x="C", ax=axes[0], logx=True)
axes[0].set_ylabel("CV 分数")
axes[0].set_title("未缩放")

## 绘制缩放 C 后的结果
for train_size_idx, label in enumerate(labels):
    results_scaled = results[[label]].assign(
        C_scaled=Cs * float(n_samples * train_sizes[train_size_idx])
    )
    results_scaled.plot(x="C_scaled", ax=axes[1], logx=True, label=label)
axes[1].set_title("将 C 按 1 / n_samples 缩放")

_ = fig.suptitle("L2 惩罚下缩放 C 的效果")

总结

本实验展示了在支持向量机(SVM)中,针对 L1 和 L2 惩罚缩放正则化参数的效果。对于 L1 惩罚,我们观察到,当用样本数量缩放 C 时,交叉验证误差与测试误差的相关性最佳。对于 L2 惩罚,最佳结果来自于不缩放 C 的情况。