Python サポートベクタマシンで非線形データを分類する

個人開発したアプリの宣伝
目的地が設定できる手帳のような使い心地のTODOアプリを公開しています。
Todo with Location

Todo with Location

  • Yoshiko Ichikawa
  • Productivity
  • Free

スポンサードリンク

以下のコードでは「Pythonではじめる機械学習」の著者が公開しているmglearnを使用します。

$ pip install mglearn



データセット

クラスタデータモデルを使用。

from sklearn.datasets import make_blobs
import mglearn
import matplotlib.pyplot as plt

X, y = make_blobs(centers=4, random_state=8)
y = y % 2

mglearn.discrete_scatter(X[:,0], X[:,1], y)
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")

f:id:letitride:20200721170651p:plain:w500

2次元でのフィッティングを行ってみても...

from sklearn.svm import LinearSVC
liner_svm = LinearSVC().fit(X, y)

mglearn.plots.plot_2d_separator(liner_svm, X)
mglearn.discrete_scatter(X[:,0], X[:,1], y)
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")

f:id:letitride:20200721171933p:plain:w500

このように現在の特徴量では線形で分類できないデータセットとなる。

但し、Feature1の特徴量を見ると、Feature1の量で分類できるようなデータセットとして受け取れる。傾向は0に近いクラスと上下に分散されているクラスがある。


Feature1の特徴量を"高さ"として扱う

片方のクラスのFeature1の特徴量が0に近いので、2乗することで特徴量を切り出し、次元追加を行う。

import numpy as np

X_new = np.hstack([X, X[:, 1:] ** 2])
from mpl_toolkits.mplot3d import Axes3D, axes3d
figure = plt.figure()
ax = Axes3D(figure, elev=-152, azim=-26)
mask = y == 0
ax.scatter(X_new[mask, 0], X_new[mask, 1], X_new[mask, 2], c="b", cmap=mglearn.cm2, s=60)
ax.scatter(X_new[~mask, 0], X_new[~mask, 1], X_new[~mask, 2], c="r", marker="^", cmap=mglearn.cm2, s=60)
ax.set_xlabel("Feature0")
ax.set_ylabel("Feature1")
ax.set_zlabel("Feature1 ** 2")

f:id:letitride:20200721171407p:plain:w500

このように次元追加を行いFeature1**2でのクラスタの纏まりが確認できる。


サポートベクタマシンで学習を行う

分類の学習を行います。

from sklearn.svm import LinearSVC
liner_svm_3d = LinearSVC().fit(X_new, y)
coef, intercept = liner_svm_3d.coef_.ravel(), liner_svm_3d.intercept_

figure = plt.figure()
ax = Axes3D(figure, elev=-152, azim=-26)

xx = np.linspace(X_new[:, 0].min() - 2, X_new[:, 0].max() + 2, 50)
yy = np.linspace(X_new[:, 1].min() - 2, X_new[:, 1].max() + 2, 50)

XX, YY = np.meshgrid(xx, yy)
ZZ = (coef[0] * XX + coef[1] * YY + intercept) / -coef[2]
ax.plot_surface(XX, YY, ZZ, rstride=8, cstride=8, alpha=0.3)
ax.scatter(X_new[mask, 0], X_new[mask, 1], X_new[mask, 2], c="b", cmap=mglearn.cm2, s=60)
ax.scatter(X_new[~mask, 0], X_new[~mask, 1], X_new[~mask, 2], c="r", marker="^", cmap=mglearn.cm2, s=60)
ax.set_xlabel("feature0")
ax.set_ylabel("feature1")
ax.set_zlabel("feature1**2")

f:id:letitride:20200721172210p:plain:w500

このように2次元では分類できないデータセットに次元追加を行い非線形データを分類することができる。


カーネル関数

また、上記の次元追加には実装を行ったんだけど、実際はサポートベクタマシンに特徴量に応じてカーネル関数を利用したりする。

from sklearn.svm import SVC
kernel_name = 'linear' # or 'rbf' or 'poly' or 'sigmoid'
liner_svm_3d = SVC(kernel=kernel_name).fit(X_train, y_train)