본문 바로가기
Python (Linux)

36. Python - 서포트 벡터 머신(라지 마진 분류)

by #Glacier 2019. 1. 31.
반응형

오늘은 5장 가장 처음인 서포트 벡터 머신(SVM, Support Vector Merchine)을 알아보겠습니다.

SVM은 매우 강력하고 선형이나 비선형 분류, 회귀, 이상치 탐색에도 사용할 수 있는 다목적 머신러닝 모델입니다.

머신러닝에서 가장 인기 있는 모델에 속하고, 머신러닝에 관심 있는 사람이라면 반드시 알고 있어야 하는 모델입니다.

SVM은 특히 복잡한 분류 문제에 잘 들어맞으며, 작거나 중간 크기의 데이터셋에 적합합니다.


1. 선형 SVM 분류


SVM의 기본 아이디어는 라지 마진 분류(Large Margin Classification)으로 나타내어 직접 보는 것이 좋습니다.

먼저, 코드를 통해 봅니다.


from sklearn.svm import SVC

from sklearn import datasets


iris = datasets.load_iris()

X = iris['data'][:, (2,3)]

y = iris['target']


setosa_or_versicolor = (y==0) | (y==1)

X = X[setosa_or_versicolor]

y = y[setosa_or_versicolor]


#SVM 분류 모델

svm_clf = SVC(kernel='linear', C=float('inf'))

svm_clf.fit(X,y)

SVC(C=inf, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
  kernel='linear', max_iter=-1, probability=False, random_state=None,
  shrinking=True, tol=0.001, verbose=False)


#나쁜 모델

import numpy as np

import matplotlib.pyplot as plt


x0 = np.linspace(0, 5.5, 200)

pred_1 = 5*x0 - 20

pred_2 = x0 - 1.8

pred_3 = 0.1 * x0 + 0.5


def plot_svc_decision_boundary (svm_clf, xmin, xmax):

    w = svm_clf.coef_[0]

    b = svm_clf.intercept_[0]

    

    #결정 경계에서 w0*x0 + w1*x1 + b = 0이므로,

    # x1 = -w0/w1 * x0  - b/w1

    

    x0 = np.linspace(xmin, xmax, 200)

    decision_boundary = -w[0]/w[1] * x0 - b/w[1]

    

    margin = 1/w[1]

    gutter_up = decision_boundary + margin

    gutter_down = decision_boundary - margin

    svs = svm_clf.support_vectors_

    plt.scatter(svs[:, 0], svs[:, 1], s=180, facecolors='#FFAAAA')

    plt.plot(x0, decision_boundary, 'k-', linewidth=2)

    plt.plot(x0, gutter_up, 'k--', linewidth=2)

    plt.plot(x0, gutter_down, 'k--', linewidth=2)

    

plt.figure(figsize=(12, 2.7))


plt.subplot(121)

plt.plot(x0, pred_1, 'g--', linewidth=2)

plt.plot(x0, pred_2, 'm-', linewidth=2)

plt.plot(x0, pred_3, 'r-', linewidth=2)

plt.plot(X[:, 0][y==1], X[:, 1][y==1], 'bs', label='Iris-Versicolor')

plt.plot(X[:, 0][y==0], X[:, 1][y==0], 'yo', label='Iris-Setosa')

plt.xlabel('꽃잎 길이', fontsize=14)

plt.ylabel('꽃잎 너비              ', fontsize=14, rotation=0)

plt.legend(loc='upper left', fontsize=14)

plt.axis([0, 5.5, 0, 2])


plt.subplot(122)

plot_svc_decision_boundary(svm_clf, 0, 5.5)

plt.plot(X[:, 0][y==1], X[:, 1][y==1], 'bs')

plt.plot(X[:, 0][y==0], X[:, 1][y==0], 'yo')

plt.xlabel('꽃잎 길이', fontsize=14)

plt.axis([0, 5.5, 0, 2])


plt.show()



왼쪽은 나쁜 예를 보여주고, 오른쪽 예는 SVM으로 분류된 그래프입니다.


왼쪽 그래프에 세 개의 선형 분류기에서 만들어진 경계가 보입니다. 

점선으로 나타난 결정 경계를 만든 모델은 클래스를 적절하게 분류하지 못하고 있음을 알 수 있죠.

하지만 다른 두 모델은 완벽히 작동하는 것을 알 수 있습니다.

하지만, 결정 경계가 너무 가까워 샘플에는 잘 작동하지 못할 것입니다.


오른쪽 그래프에 있는 실선은 SVM 분류기의 결정 경계입니다. 

이 직선은 두 개의 클래스를 나누고 있을 뿐만 아니라, 제일 가까운 훈련샘플로부터 가능한 멀리 떨어져 있습니다.

이렇게 SVM분류기를 클래스 사이의 폭이 넓은 도로를 찾는 것으로 생각하여, 

'라지 마진 분류(Large Margin Classification)'이라고 합니다.


도로 바깥쪽에 훈련 샘플을 더 추가해도, 결정 경계에는 전혀 영향을 미치지 않습니다.

도로 경계에 위치한 샘플에 의해 전적으로 결정 (또는 의지) 됩니다. 이런 샘플을 서포트 벡터(Support Vector)라고 합니다.

(오른쪽 그래프에서 동그라미 그려진 부분)


##NOTE 

SVM은 특성의 스케일에 민감합니다. 왼쪽 그래프에서는 수직축의 스케일이 수평축의 스케일보다 훨씬 커서,

가장 넓은 도로가 거의 수평에 가깝게 됩니다. 특성의 스케일을 조정하면, 결정 경계가 훨씬 좋아질 수 있습니다.


아래는 스케일 조정이 왜 중요한지, 보여주는 코드입니다.


Xs = np.array([[1, 50], [5, 20], [3, 80], [5, 60]]).astype(np.float64)

ys = np.array([0,0,1,1])

svm_clf = SVC(kernel='linear', C=100)

svm_clf.fit(Xs, ys)


plt.figure(figsize=(12,3.2))

plt.subplot(121)


#Xs의 행 전체, 0열을 가져오는데 ys가 1인 것만 가져옵니다. 

plt.plot(Xs[:, 0][ys==1], Xs[:, 1][ys==1], 'bo')

#Xs의 행 전체, 0열을 가져오되 ys가 0인 것만 가져옵니다.

plt.plot(Xs[:, 0][ys==0], Xs[:, 1][ys==0], 'ms')

plot_svc_decision_boundary(svm_clf, 0, 6)

plt.xlabel('$x_0$', fontsize=20)

plt.ylabel('$x_1$        ', fontsize=20, rotation=0)

plt.title('스케일 조정 전', fontsize=16)

plt.axis([0,6,0,90])


from sklearn.preprocessing import StandardScaler


scaler = StandardScaler()

X_scaled = scaler.fit_transform(Xs)

svm_clf.fit(X_scaled, ys)


plt.subplot(122)

plt.plot(X_scaled[:, 0][ys==1], X_scaled[:,  1][ys==1], 'bo')

plt.plot(X_scaled[:, 0][ys==0], X_scaled[:,  1][ys==0], 'ms')

plot_svc_decision_boundary(svm_clf, -2, 2)

plt.xlabel('$x_0$', fontsize=20)

plt.title('스케일 조정 후', fontsize=16)

plt.axis([-2, 2, -2, 2])



 블로그 

출처


이 글의 상당 부분은  [핸즈온 머신러닝, 한빛미디어/오렐리앙 제롱/박해선] 서적을 참고하였습니다.


나머지는 부수적인 함수나 메서드에 대해 부족한 설명을 적어두었습니다.

학습용으로 포스팅 하는 것이기 때문에 복제보다는 머신러닝에 관심이 있다면 구매해보시길 추천합니다.


도움이 되셨다면 로그인 없이 가능한

아래 하트♥공감 버튼을 꾹 눌러주세요! 



반응형