최종 수정 일자: 2020-06-14 16:21
해당 카테고리에 작성되는 글은 Introduction to Machine Learning with Python(파이썬 라이브러리를 활용한 머신 러닝)을 기반으로 작성되었습니다.
Kernelized support vector machine (KSVM)은 입력 공간 내에서 초평면(hyperplane)으로 단순하게 정의되지 않는 더 복잡한 모델링을 가능하게 하는 SVM의 확장된 알고리즘입니다. 분류의 경우 SVC로, 회귀의 경우 SVR을 이용합니다.
KSVM을 뒷받침하는 수학적 사실들은 이 학습의 범위를 벗어나는 것이므로 다루지 않습니다.
Linear model과 비선형 특성
Linear model을 더 유연하게 만드는 방법은 특성을 추가하는 것입니다. 예를 들어, 입력 특성들로 만들 수 있는 곱 또는 다항식을 새로운 특성으로 추가할 수 있습니다.
from sklearn.datasets import make_blobs 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") plt.show() |
결과)
분류를 위한 linear model은 직선을 이용하여 데이터 포인트를 분리하며 이 데이터 셋에서는 잘 작동하지 않는다는 것을 알 수 있습니다.
from sklearn.datasets import make_blobs X, y = make_blobs(centers=4, random_state=8) y = y % 2 from sklearn.svm import LinearSVC linear_svm = LinearSVC().fit(X, y) mglearn.plots.plot_2d_separator(linear_svm, X) mglearn.discrete_scatter(X[:, 0], X[:, 1], y) plt.xlabel("Feature 0") plt.ylabel("Feature 1") plt.show() |
결과)
이제 새로운 입력 특성을 추가하여 확장해봅시다. feature 1을 제곱한 새로운 특성 feature 1**2을 추가하여 새로운 3차원 데이터 셋을 만듭니다.
from sklearn.datasets import make_blobs X, y = make_blobs(centers=4, random_state=8) y = y % 2 # add the squared first feature X_new = np.hstack([X, X[:, 1:] ** 2]) from mpl_toolkits.mplot3d import Axes3D, axes3d figure = plt.figure() # visualize in 3D ax = Axes3D(figure, elev=-152, azim=-26) # plot first all the points with y == 0, then all with y == 1 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") plt.show() |
결과)
이로부터 linear model을 사용하여 두 개의 class로 분류할 수 있습니다.
from sklearn.datasets import make_blobs X, y = make_blobs(centers=4, random_state=8) y = y % 2 # add the squared first feature X_new = np.hstack([X, X[:, 1:] ** 2]) from sklearn.svm import LinearSVC linear_svm_3d = LinearSVC().fit(X_new, y) coef, intercept = linear_svm_3d.coef_.ravel(), linear_svm_3d.intercept_ # show linear decision boundary from mpl_toolkits.mplot3d import Axes3D, axes3d figure = plt.figure() mask = y == 0 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("feature0 ** 2") plt.show() |
결과)
원래 특성의 함수로서 이 linear SVM 모델은 실제로 더 이상 선형이 아닙니다. 일종의 타원형으로 경계가 만들어지며 아래의 그림에서 확인할 수 있습니다.
from sklearn.datasets import make_blobs X, y = make_blobs(centers=4, random_state=8) y = y % 2 # add the squared first feature X_new = np.hstack([X, X[:, 1:] ** 2]) from sklearn.svm import LinearSVC linear_svm_3d = LinearSVC().fit(X_new, y) coef, intercept = linear_svm_3d.coef_.ravel(), linear_svm_3d.intercept_ figure = plt.figure() mask = y == 0 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 = YY ** 2 dec = linear_svm_3d.decision_function(np.c_[XX.ravel(), YY.ravel(), ZZ.ravel()]) plt.contourf(XX, YY, dec.reshape(XX.shape), levels=[dec.min(), 0, dec.max()], cmap=mglearn.cm2, alpha=0.5) mglearn.discrete_scatter(X[:, 0], X[:, 1], y) plt.xlabel("Feature 0") plt.ylabel("Feature 1") plt.show() |
결과)
Kernel Trick
보유한 데이터 셋에 비선형 특성을 추가하는 linear model을 더욱 강하게 만들어 줍니다. 그러나 어떤 특성을 어떤 처리를 통해서 새로운 특성으로 만들어 더해야 할지를 모르는 상황이며 많은 특성을 추가해버리면 계산을 매우 비효율적으로 만듭니다. 다행히도 더 높은 차원의 공간으로 확장시킬 수 있는 현명한 수학적 트릭이 있습니다. 이들은 kernel trick으로 불리며 확장된 특성 표현을 위해 직접적으로 데이터 포인트들의 스칼라 곱 거리를 계산함으로써 작동합니다.
일반적으로 support vector machine에서 사용되는 차원 공간 확장에 사용되는 두 가지 방법은 polynomial kernel과 radial basis function (RBF) kernel입니다. Polynomial kernel은 원래의 특성으로 특정 차수만큼의 가능한 모든 polynomial을 계산합니다. RBF kernel은 Gaussian kernel로도 알려져 있으며 무한한 차원의 특성 공간에 대응하므로 설명하기 어려운 감이 있습니다. 모든 차수의 가능한 polynomial을 고려하지만 높은 차원에서의 특성 중요도가 줄어들게 됩니다.
KSVM의 수학적 디테일은 그렇게 중요하지 않습니다만 RBF kernel의 SVM이 결정을 어떻게 만드는지는 쉽게 요약할 수 있습니다.
SVM 이해하기
SVM은 각 학습 데이터 포인트가 두 class 사이의 결정 경계를 대표하는데 얼마나 중요한지를 학습합니다. 보통 데이터 포인트의 어떤 부분집합만이 결정 경계를 정의하는데 중요합니다. 즉, class 사이의 경계에 놓인 데이터 포인트만이 중요해지며 이들을 support vector라 합니다.
새로운 데이터 포인트에 대한 예측을 만들기 위해서 각 support vector와의 거리를 측정합니다. 분류 결정은 이 거리와 support vector의 중요도에 기반하여 만들어집니다. 이 정보는 dual_coef_에 저장됩니다.
Gaussian kernel에 의해 측정되는 데이터 포인트 사이의 거리는 다음과 같습니다.
x1과 x2는 데이터 포인트를 말하며 ||x1 – x2||는 Euclidean distance를, γ는 Gaussian kernel의 너비를 조절하는 매개변수입니다.
다음의 그림은 2차원의 두 개의 class를 갖는 데이터 셋을 이용한 SVM의 학습 결과를 보여줍니다.
X, y = mglearn.tools.make_handcrafted_dataset() from sklearn.svm import SVC svm = SVC(kernel='rbf', C=10, gamma=0.1).fit(X, y) mglearn.plots.plot_2d_separator(svm, X, eps=.5) mglearn.discrete_scatter(X[:, 0], X[:, 1], y) # plot support vectors sv = svm.support_vectors_ # class labels of support vectors are given by the sign of the dual coefficients sv_labels = svm.dual_coef_.ravel() > 0 mglearn.discrete_scatter(sv[:, 0], sv[:, 1], sv_labels, s=15, markeredgewidth=3) plt.xlabel("Feature 0") plt.ylabel("Feature 1") plt.show() |
결과)
이 경우 SVM은 매우 부드럽고 비선형의 경계를 만듭니다. 이때 두 매개변수 C와 gamma를 조절하였습니다.
SVM 매개변수 조절
gamma 매개변수는 이전 파트의 공식에서 등장했던 Gaussian kernel의 너비를 조절하며 데이터 포인트 사이의 거리가 가까운 정도를 결정합니다. C 매개변수는 정규화 매개변수로 linear model에서 사용했던 것과 유사합니다. 각 포인트의 중요도, 즉 dual_coef_를 제한하는 역할을 합니다.
fig, axes = plt.subplots(3, 3, figsize=(15, 10)) for ax, C in zip(axes, [-1, 0, 3]): for a, gamma in zip(ax, range(-1, 2)): mglearn.plots.plot_svm(log_C=C, log_gamma=gamma, ax=a) axes[0, 0].legend(["class 0", "class 1", "sv class 0", "sv class 1"], ncol=4, loc=(.9, 1.2)) plt.show() |
결과)
좌측에서 우측으로 가면 gamma가 0.1에서 10까지 변합니다. 작은 gamma는 Gaussian kernel의 큰 radius를 의미하며 많은 데이터 포인트가 서로 가까운 것으로 간주됩니다. 이는 오른쪽으로 갈수록 단일 데이터 포인트 자체에 집중하는 경계를 통해 확인할 수 있습니다. 작은 gamma값은 결정 경계가 느리게 변하며 이는 낮은 복잡도의 모델을 만들게 됩니다. 큰 gamma값은 복잡도가 높은 모델을 만듭니다.
위에서 아래로 가면 C가 0.1에서 1000까지 변합니다. Linear model과 마찬가지로 작은 C값은 매우 제한된 모델을 의미하며 각 데이터 포인트가 제한적인 영향을 갖습니다. 좌측 상단의 결정 경계는 직선에 가까우며 C를 증가시킬수록 각 포인트가 모델에 주는 영향력이 강해져 정확도가 높아집니다.
from sklearn.datasets import load_breast_cancer cancer = load_breast_cancer() from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, random_state=0) from sklearn.svm import SVC svc = SVC() svc.fit(X_train, y_train) print("Accuracy on training set: {:.2f}".format(svc.score(X_train, y_train))) print("Accuracy on test set: {:.2f}".format(svc.score(X_test, y_test))) |
결과)
Accuracy on training set: 0.90 Accuracy on test set: 0.94 |
svm은 잘 작동하지만 매개변수의 설정과 데이터의 스케일링에 매우 민감합니다. 특히, 모든 특성이 비슷한 스케일에서 변할 것을 요구합니다. 각 특성의 최댓값과 최솟값이 어떻게 이루어지는지 살펴봅시다.
from sklearn.datasets import load_breast_cancer cancer = load_breast_cancer() from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, random_state=0) plt.plot(X_train.min(axis=0), 'o', label="min") plt.plot(X_train.max(axis=0), '^', label="max") plt.legend(loc=4) plt.xlabel("Feature index") plt.ylabel("Feature magnitude") plt.yscale("log") plt.show() |
결과)
SVM 데이터 전처리
각 특성을 rescaling하여 이러한 문제를 해결할 수 있습니다. KSVM에 사용되는 일반적인 rescaling 방법은 모든 특성이 0과 1 사이의 값을 갖도록 변환하는 것입니다.
from sklearn.datasets import load_breast_cancer cancer = load_breast_cancer() from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, random_state=0) # compute the minimum value per feature on the training set min_on_training = X_train.min(axis=0) # compute the range of each feature (max - min) on the training set range_on_training = (X_train - min_on_training).max(axis=0) # subtract the min, and divide by range # afterward, min=0 and max=1 for each feature X_train_scaled = (X_train - min_on_training) / range_on_training print("Minimum for each feature\n{}".format(X_train_scaled.min(axis=0))) print("Maximum for each feature\n{}".format(X_train_scaled.max(axis=0))) # use THE SAME transformation on the test set, using min and range of the training set X_test_scaled = (X_test - min_on_training) / range_on_training from sklearn.svm import SVC svc = SVC() svc.fit(X_train_scaled, y_train) print("Accuracy on training set: {:.3f}".format(svc.score(X_train_scaled, y_train))) print("Accuracy on test set: {:.3f}".format(svc.score(X_test_scaled, y_test))) |
결과)
Minimum for each feature [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] Maximum for each feature [1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] Accuracy on training set: 0.984 Accuracy on test set: 0.972 |
데이터를 재스케일링 해주기만 해도 큰 차이를 만들어낼 수 있습니다. 이제 매개변수를 조절하여 모델 복잡도를 조절해봅시다.
from sklearn.datasets import load_breast_cancer cancer = load_breast_cancer() from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, random_state=0) min_on_training = X_train.min(axis=0) range_on_training = (X_train - min_on_training).max(axis=0) X_train_scaled = (X_train - min_on_training) / range_on_training X_test_scaled = (X_test - min_on_training) / range_on_training from sklearn.svm import SVC svc = SVC(C=1000) svc.fit(X_train_scaled, y_train) print("Accuracy on training set: {:.3f}".format(svc.score(X_train_scaled, y_train))) print("Accuracy on test set: {:.3f}".format(svc.score(X_test_scaled, y_test))) |
결과)
결과 이상.. |
장점, 단점, 매개변수
KSVM은 다양한 데이터 셋 위에서 잘 작동한다는 장점이 있습니다. SVM은 복잡한 결정 경계를 허용하며 차원에 상관없이 잘 작동하지만 샘플 수에 영향을 받습니다. 10000개의 샘플까지는 SVM이 잘 작동하지만 10만개 이상의 크기를 갖는 데이터 셋에 대해서는 학습 시간 및 메모리 사용이 커진다는 단점이 있습니다.
SVM의 또 다른 단점은 데이터의 전처리 및 매개변수의 조절에 주의를 기울여야 된다는 것입니다. 때문에 많은 사람들이 SVM 대신 트리 기반 모델을 사용합니다. 또한 SVM 모델은 검정이 어렵다는 단점이 있습니다. 왜 특정 예측이 만들어지는지 이해하기가 어려울 수 있으며 비전문가에게 모델을 설명하기도 어렵습니다.
KSVM의 중요한 매개변수는 정규화 변수 C, kernel의 선택, 및 각 kernel에서 규정되는 매개변수들입니다. RBF kernel에 대해서만 다뤘지만 scikit-learn에서 이용 가능한 다른 선택들이 있습니다. RBF kernel은 gamma와 C 매개변수로 모델의 복잡도를 조절할 수 있습니다.
'Python-머신 러닝 > Python-지도 학습 알고리즘' 카테고리의 다른 글
2. 지도 학습 알고리즘 (6) Ensembles of Decision Trees (Gradient Boosted Regression Trees) (0) | 2020.06.14 |
---|---|
2. 지도 학습 알고리즘 (5) Ensembles of Decision Trees (Random Forest) (0) | 2020.06.14 |
2. 지도 학습 알고리즘 (4) Decision Trees (0) | 2020.06.14 |
2. 지도 학습 알고리즘 (3) Naive Bayes Classifiers (0) | 2020.06.14 |
2. 지도 학습 알고리즘 (2) Linear Model (0) | 2020.06.14 |