SVM における正則化パラメータのスケーリング

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 はサンプルとモデルパラメータの損失関数です
  • Ω はモデルパラメータのペナルティ関数です

VM のヒント

VM の起動が完了したら、左上隅をクリックして ノートブック タブに切り替えて、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))

## plot results without scaling C
results.plot(x="C", ax=axes[0], logx=True)
axes[0].set_ylabel("CV score")
axes[0].set_title("No scaling")

## plot results by scaling 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("Scaling C by 1 / n_samples")

_ = fig.suptitle("Effect of scaling C with L1 penalty")

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))

## plot results without scaling C
results.plot(x="C", ax=axes[0], logx=True)
axes[0].set_ylabel("CV score")
axes[0].set_title("No scaling")

## plot results by scaling 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("Scaling C by 1 / n_samples")

_ = fig.suptitle("Effect of scaling C with L2 penalty")

まとめ

この実験では、L1 および L2 ペナルティの両方に対して、SVM における正則化パラメータをスケーリングする効果を示しました。L1 ペナルティの場合、サンプル数で C をスケーリングするとき、交差検証誤差がテスト誤差と最も相関することが観察されました。L2 ペナルティの場合、最良の結果は C をスケーリングしない場合から得られます。