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,) 형태로 출력되게 된다.
- 그래프에서 보이는 선은 선형 결정 경계로 소프트 벡터 머신에서 중요하게 생각하는 것이다.
- 넓은 마진(두 데이터 포인터와 경계가 떨어진 정도)을 가지는 것이 안정적이며, 모든 클래스를 구분할 수 있어야 한다.
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
'머신러닝 in Python' 카테고리의 다른 글
[Python] Grid Search (0) | 2019.08.30 |
---|---|
[Python] Cross-validation(교차검증) (1) | 2019.08.30 |
[Python] 분류분석 - logistic regression (0) | 2019.08.28 |
[Python] LinearRegression(수치예측) - Lasso (0) | 2019.08.28 |
[Python] LinearRegression(수치예측) - Ridge (0) | 2019.08.28 |