🦎
SVMのCパラメータについて雑に試してみた
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