🦎

SVMのCパラメータについて雑に試してみた

2022/01/28に公開

SVMのCパラメーターをいじるといったいどうなるのか試してみた。
もろもろ雑にやってるのはスルーで。

必要なライブラリ

import numpy as np
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
from sklearn.svm import SVC

適当なサンプルデータを作る

2クラスターでちょっとだけノイジーなデータを作った。

xs, ys = make_blobs(n_samples=1_000, centers=2, cluster_std=2, random_state=2022)

可視化すると

plt.scatter(xs[:, 0], xs[:, 1], c=ys, s=10, cmap=plt.cm.coolwarm)
plt.show()

LinearSVCで判別

してみると、まあそれなりに分けられる。

clf = SVC(kernel='linear')
clf.fit(xs, ys)
preds = clf.predict(xs)

plt.scatter(xs[:, 0], xs[:, 1], c=preds, s=10, cmap=plt.cm.coolwarm)
plt.show()

識別境界の可視化

SVCの識別境界を可視化してみる。
sklearnに良い説明があったのでこれを参考にしてみた。

ノイズになってる部分がちょっと判別できていない。

def simulate(clf, x_min, x_max, y_min, y_max):
    xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01), np.arange(y_min, y_max, 0.01))

    fig, ax = plt.subplots()
    z = clf.predict(np.array([xx.ravel(), yy.ravel()]).T)
    ax.contourf(xx, yy, z.reshape(xx.shape), alpha=0.2, cmap=plt.cm.coolwarm)
    ax.scatter(xs[:, 0], xs[:, 1], c=ys, s=10, cmap=plt.cm.coolwarm)
    plt.show()
    
simulate(clf, x_min=-17, x_max=1, y_min=-16, y_max=6)

Cパラメータをいじる

Cパラメータは誤識別数を減らすためのペナルティパラメータなので、C=5, 20, 100にして結果を見てみる。

def simulate_svc(kernel, x_min, x_max, y_min, y_max):
    xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01), np.arange(y_min, y_max, 0.01))

    fig, ax = plt.subplots(1, 4, figsize=(20, 5))

    for i, c in enumerate([1, 5, 20, 100]):
        clf = SVC(kernel=kernel, C=c)
        clf.fit(xs, ys)
        z = clf.predict(np.array([xx.ravel(), yy.ravel()]).T)
        ax[i].contourf(xx, yy, z.reshape(xx.shape), alpha=0.2, cmap=plt.cm.coolwarm)
        ax[i].scatter(xs[:, 0], xs[:, 1], c=ys, s=10, cmap=plt.cm.coolwarm)
        ax[i].set_title(f'kernel={kernel}, C={c}')

    plt.show()
    
for k in ['linear', 'poly', 'rbf', 'sigmoid']:
    simulate_svc(kernel=k, x_min=-17, x_max=1, y_min=-16, y_max=6)

  • LinearSVMのままだとCを変えてもほとんど影響がない。
  • polyはCをでかくすると境界が直線に近づいた。

  • rbfだとちょっとノイズ部分に境界がひっぱられる? Cがでかいと今見えているデータに境界が引っ張られてる?
  • sigmoidはそもそもが

さらにノイジーデータで試す

xs, ys = make_blobs(n_samples=1_000, centers=2, cluster_std=3, random_state=2022)
plt.scatter(xs[:, 0], xs[:, 1], c=ys, s=10, cmap=plt.cm.coolwarm)
plt.show()

for k in ['linear', 'poly', 'rbf', 'sigmoid']:
    simulate_svc(kernel=k, x_min=-20, x_max=3, y_min=-20, y_max=10)

ちょっとノイジーな時とそんなに違い見えない?

結果

  • 今回はCをでかくするとそんなに大きく境界面が変わっては見えなかった。
  • rbfはCを大きくすると境界全体が既存データに引っ張られているように見えた。
  • svmも可視化は大事

Discussion