Support Vector Machine

  • 기계 학습의 분야 중 하나로 패턴 인식, 자료 분석을 위한 지도 학습 모델
  • 주로 분류와 회귀분석을 위해 사용
  • 선형 분류와 비선형 분류에서도 사용

 

 

1. 선형 SVM 

  • parameter C를 조정해 과대적합 혹은 과소적합 문제를 해결
  • C(cost function) 값이 크면(높은 코스트) -> 훈련을 더 복잡하게-> 약한 규제
  • C 값이 작으면(낮은 코스트) -> 훈련을 덜 복잡하게 -> 강한 규제

 

from sklearn.svm import LinearSVC
from sklearn import datasets
from mlxtend.plotting import category_scatter
import pandas as pd
import numpy as np


# 1. toy dataset 생성
X, y = datasets.make_blobs(random_state=42)


# 2. 데이터 프레임으로 만들기
df = pd.DataFrame(X, columns=['feature0', 'feature1'])
df['class'] = y
df


# 3. 그래프 확인
category_scatter(x='feature0', y='feature1', label_col='class',data=df,legend_loc='lower right')

- 그래프를 확인하면 y가 3가지의 값을 가지는 것을 보고 클래스가 3개임을 알 수 있다.

- 클래스별 데이터들의 분포를 확인하는 그래프이다.

 

 

 

 

# 4. 모델링
linear_svm=LinearSVC().fit(X,y) # C=1.0


# 5.1 클래스별 계수 확인
linear_svm.coef_


# 5.2 클래스별 절편
linear_svm.intercept_

# 그래프

import matplotlib.pyplot as plt

line = np.linspace(-15, 15) # 지정된 간격 동안 균일 한 간격의 숫자를 반환합니다.

fig, ax = plt.subplots()
scatter = ax.scatter(X[:,0], X[:,1],c = y, s = 50)

for coef, intercept, color in zip(linear_svm.coef_,
                                 linear_svm.intercept_,
                                 ["black","blue","red"]):
    ax.plot(line, -(line*coef[0]+intercept)/coef[1], c = color)
ax.set_ylim(-10, 15)
ax.set_xlim(-10, 8)
ax.legend(*scatter.legend_elements(), loc = "best", title = "class")

- coef_ : 클래스별 계수 즉, ax+b 에서 a를 의미하며, (3,2)의 형태로 출력되게 된다.

- intercept_ : 클래스별 절편으로 즉, ax+b에서 b를 의미하며, (3,) 형태로 출력되게 된다.

 

 

 default  (C = 1.0 ) 인 결과

- 그래프에서 보이는 선은 선형 결정 경계로 소프트 벡터 머신에서 중요하게 생각하는 것이다.

- 넓은 마진(두 데이터 포인터와 경계가 떨어진 정도)을 가지는 것이 안정적이며, 모든 클래스를 구분할 수 있어야 한다. 

 

 

from mlxtend.plotting import plot_decision_regions

# 최종 그래프 확인
plot_decision_regions(X=X, y=y, clf=linear_svm, legend=4)
plt.title('SVC Decision Region Boundary', size=15)

- 최종 그래프를 면으로 확인해보면 위와 같은 그래프 형태를 나타나게 된다.

 

 

 

2. SVM

# 1. toy 데이터
X, y = datasets.make_blobs(centers=4, random_state=8)
y = y%2

# 그래프 확인
plt.scatter(X[:,0],X[:,1],c=y,s=50,edgecolors="b")

 

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm

# 2. 2번째 특성 제곱하여 추가
X_new = np.hstack([X,X[:,1:]**2]) # 제곱을 새로운 열로 만들어 줌
X_new

# 그래프 확인
figure = plt.figure()
ax = Axes3D(figure, elev=-162, azim=-26) # 각도 틀어주는 파라미터 
mask = y==0
ax.scatter(X_new[mask,0], X_new[mask,1], X_new[mask,2], c='b', s=60, edgecolor='k')
ax.scatter(X_new[~mask,0], X_new[~mask,1], X_new[~mask,2], c='r', marker = '^', s=60, edgecolor='k')
ax.set_xlabel('feature0')
ax.set_ylabel('feature1')
ax.set_zlabel('feature0 ** 2')

 

- 1번째 열의 값을 제곱하여 2번째 열로 붙이는 작업 수행

- 3D 그래프를 위해 Axes3D를 이용함

- y 는 0과 1인 2개의 클래스 -> mask를 통하여 y가 0인지 1인지를 구분하여 0인 행은 파란색, 1인 행은 빨간색으로 표시

 

linear_svm_3d = LinearSVC(max_iter=10000).fit(X_new,y)
coef, intercept = linear_svm_3d.coef_.ravel(), linear_svm_3d.intercept_
# 선형 결정 경계 그려주기

figure = plt.figure()
ax = Axes3D(figure, elev=-140, 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)
# 평면 그려주기 위해 조금 범위 넓게 (+2) 만큼 해줌

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,cmap=cm.Accent)

ax.scatter(X_new[mask,0], X_new[mask,1], X_new[mask,2], c='b', s=60, edgecolor='k')
ax.scatter(X_new[~mask,0], X_new[~mask,1], X_new[~mask,2], c='r', marker = '^', s=60, edgecolor='k')
ax.set_xlabel('feature0')
ax.set_ylabel('feature1')
ax.set_zlabel('feature0 ** 2')

 

 

 

**주요 parameter

  • gamma :가우시안 커널의 반경을 결정.

    감마 값이 크면 커널의 반경 좁아짐 -> 훈련에 각각의 데이터 포인트를 더욱 반영 -> 복잡한 증가

    감마 값이 작으면 커널의 반경 넓어짐 -> 훈련에 더 넓은 면적에 걸친 데이터 포인트를 반영 -> 복잡도 감소

  • C: cost function 과 동일

즉,  C는 데이터 샘플들이 다른 클래스에 놓이는 것을 허용하는 정도를 결정, gamma는 결정 경계의 곡률을 결정

 

 

 

* 정규화 : 

# 모든 특성 정규화

# 1) 트레인 데이터 특성별 최소값/최대값 추출
X_train_min = X_train.min(axis = 0)
X_train_max = X_train.max(axis = 0)

# 2) 트레인 데이터 특성별 범위
X_train_range = X_train_max - X_train_min

# 3) 트레인 데이터 정규화
X_train_scaled = (X_train-X_train_min)/X_train_range

# 4) 정규화 확인
print("특성별 최소값\n {}".format(X_train_scaled.min(axis=0)))
print("특성별 최대값\n {}".format(X_train_scaled.max(axis=0)))

# 5) 테스트 데이터 정규화
X_test_scaled = (X_test - X_train_min)/X_train_range

-  5) 테스트 데이터 정규화는 train 데이터의 범위로 계산해줌

-> test 데이터를 범위로 하게 되면 들어올 때마다 값이 변경되기 때문에 train 데이터 범위를 사용하는 것이다. ( + train 데이터의 추출양이 많아 데이터를 잘 설명한다고 할 수 있다. )

만약, train 데이터보다 test 데이터가 더 많은 경우 test는 test의 범위를 사용하는 것이 좋을 수도 있다.

# 5) 테스트 데이터 정규화 
X_test_scaled = (X_test - X_test.min(axis=0))/(X_test.max(axis=0)-X_test.min(axis=0))

+ 추가로, 정규화 가정은 sklearn.preprocessing.MinMaxScaler() 를 통해 사용 가능

 

 

 

참고 사이트 : https://bskyvision.com/163 

 

+ Recent posts