Data Analysis & ML/Machine Learning

[Machine Learning][머신러닝][지도학습] SVM(Support Vector Machine)

YSY^ 2020. 9. 1. 15:11

Support Vector Machine (SVM)

선형(Linear) SVM

  • 딥러닝 이전에 분류에서 뛰어난 성능으로 가장 활용도가 높았던 분류모델
  • 하나의 분류 그룹을 다른 그룹과 분리하는 최적의 경계를 찾아내는 알고리즘
  • 중간크기의 데이터셋과 특성(Feature)이 많은 복잡한 데이터셋에서 성능이 좋은 것으로 알려져있다.

선 (1)과 (2)중 어떤 선이 최적의 분류 선일까?

목표: support vector간의 가장 넓은 margin을 가지는 초평면(결정경계)를 찾는다.

초평면

  • 데이터가 존재하는 공간보다 1차원 낮은 부분공간
    • n차원의 초평면은 n-1차원
    • 공간을 나누기 위해 초평면을 사용한다.
    • 1차원-점, 2차원-선, 3차원-평면, 4차원이상 초평면
  • Support Vector: 경계를 찾아내는데 기준이 되는 데이터포인트. 초평면(결정경계)에 가장 가까이 있는 vector(데이터포인트)를 말한다.
  • margin : 두 support vector간의 너비
  • margin이 넓은 결정경계를 만드는 함수를 찾는 것.

Hard Margin, Soft Margin

  • Overfitting(과적합)을 방지하기 위해 어느정도 오차를 허용하는 방식을 Soft margin이라고 한다. 반대로 오차를 허용하지 않는 방식을 Hard Margin이라고 한다.
  • 모든 데이터셋이 위 그림 처럼 완전히 분류 되는 것은 아니다.
  • 노이즈가 있는 데이터나 선형적으로 분리 되지 않는 경우 하이퍼파마미터인 C 조정해 마진을 변경한다.
  • C
    • 기본값 1
    • 파라미터값을 크게주면 마진폭이 좁아져 마진 오류가 작아지나 Overfitting이 일어날 가능성이 크다.
    • 파라미터값을 작게 주면 마진폭이 넓어져 마진 오류가 크다. 훈련데이터에서는 성능이 안좋아지나 일반화(generalization)되어 테스트 데이터의 성능이 올라간다. 그러나 underfitting 이 날 가능성이 있다.

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.svm import SVC, LinearSVC

cancer = load_breast_cancer()
X_train, X_test, y_train, y_test =\
train_test_split(cancer.data, cancer.target, stratify=cancer.target)


# Scaling
# scaler = MinMaxScaler()
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

svm = SVC(kernel='linear') #선형 SVM
# svm = LinearSVC()
svm.fit(X_train_scaled, y_train)
pred_train = svm.predict(X_train_scaled)
pred_test = svm.predict(X_test_scaled)

pred_test = svm.predict(X_test_scaled)
from sklearn.metrics import accuracy_score
print("train정확도:", accuracy_score(y_train, pred_train))
print('test정확도:', accuracy_score(y_test, pred_test))
train정확도: 0.9929577464788732
  • MinMaxScaler
    train정확도: 0.9812206572769953
    test정확도: 0.972027972027972

  • StandardScaler
    train정확도: 0.9929577464788732
    test정확도: 0.972027972027972

C 의 변화에 따른 성능 확인

# 클수록 Hard margin
C_list = [0.01, 0.05, 0.1, 0.5, 1, 10]


train_acc_list = []
test_acc_list = []
for C in C_list:
    svc = SVC(kernel='linear', C=C)
    svc.fit(X_train_scaled, y_train)

    train_acc_list.\
    append(accuracy_score(y_train, svc.predict(X_train_scaled)))
    test_acc_list.\
    append(accuracy_score(y_test, svc.predict(X_test_scaled)))

import pandas as pd
d = dict(C=C_list, 
         train_정확도=train_acc_list, 
         test_정확도=test_acc_list)
df = pd.DataFrame(d)
df

 

import matplotlib.pyplot as plt
df.set_index('C').plot(figsize=(7,6))
plt.xlim(0,1.5)
plt.show()

 

 

커널 서포트 벡터 머신

비선형데이터 셋에 SVM 적용

  • 선형으로 분리가 안되는 경우는?

 

  • 다항식 특성을 추가하여 차원을 늘려 선형 분리가 되도록 변환

 

[원래 공간으로 변환]

 

차원을 늘리는 경우의 문제

  • 다항식 특성을 추가하는 방법은 낮은 차수의 다항식은 데이터의 패턴을 잘 표현하지 못해 과소적합이 너무 높은 차수의 다항식은 과대적합과 모델을 느리게 하는 문제가 있다.

커널 트릭(Kernel trick)

  • 다항식을 만들기 위한 특성을 추가하지 않으면서 수학적 기교를 적용해 다항식 특성을 추가한 것과 같은 결과를 얻을 수있다.
  • 이런 방식을 커널 트릭이라고 한다.

방사기저(radial base function-RBF) 함수

  • 커널 서포트 벡터 머신의 기본 커널 함수
  • 기준점들이 되는 위치를 지정하고 각 샘플이 그 기준점들과 얼마나 떨어졌는 지를 계산한다. => 유사도(거리)
  • 기준점 별 유사도 계산한 값은 원래 값보다 차원이 커지고 선형적으로 구분될 가능성이 커진다.

  • rbf(radial basis function) 하이퍼파라미터
    • C
      • 오차 허용기준. 작은 값일 수록 많이 허용한다.
      • 과적합일 경우 값을 감소시키고, 과소적합일 경우 값을 증가 시킨다.
    • gamma
      • 방사기저함수의 $\gamma$로 규제의 역할을 한다.
      • 모델이 과대적합일 경우 값을 감소시키고, 과소적합일 경우 값을 증가시킨다.

Guide

  • 커널 기법은 다항식 차수를 만드는 것이 아니라 각 샘플을 함수에 넣어 나오는 값으로 같은 효과를 가지게 한다.
  • C는 과적합이면 훈련셋에 타이트하게 맞춘 것이므로 오차허용을 좀 늘려서 공간을 확보해야 하므로 값을 줄인다. (작은 값일 수록 많이 허용)
    과소적합이면 너무 오차허용을크게 잡은 것이므로 오차허용을 줄여야 하므로 값을 늘린다. (큰값은 적게 허용)
  • gamma 방사 기저함수 공식상 감마가 크면 반환값은 작아지고 감마가 작으면 반환값은 커진다. ($-\gamma$ 를 곱하므로)
    • 감마가 작을 수록 값들의 거리가 멀어지고(큰값이 결과로 나오므로) 클 수록 거리가 가까워진다. 그래서 gamma 가 크면 거리가 타이트해져 과적합이 일어날 수있다. (공간의 여유가 없므으로)
    • svm - 비선형 분리와 rbf 테스트.ipynb 문서 확인
from sklearn.svm import SVC

rbf_model = SVC(kernel='rbf',  random_state=12, 
                gamma='auto', probability=True)  #auto: 1/컬럼수, scale: 1/(컬럼수*X분산값)
rbf_model.fit(X_train_scaled, y_train)

# 평가
from sklearn.metrics import accuracy_score, confusion_matrix, roc_auc_score

pred_train = rbf_model.predict(X_train_scaled)
pred_test = rbf_model.predict(X_test_scaled)

print("Train 정확도 : ", accuracy_score(y_train, pred_train))
print('Test 정확도 : ', accuracy_score(y_test, pred_test))
Train 정확도 :  0.9859154929577465
Test 정확도 :  0.958041958041958

confusion_matrix(y_train, pred_train)
#array([[153,   6],
#       [  0, 267]], dtype=int64)

confusion_matrix(y_test, pred_test)
#array([[52,  1],
#       [ 5, 85]], dtype=int64)

GridSearch로 최적의 조합찾기

from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC

param_grid = {'kernel':['rbf','linear'],
              'C':[0.001,0.01,0.1,1,10,100],
             'gamma':[0.001,0.01,0.1,1,10,100]}

svm = SVC()
g_search = GridSearchCV(svm, 
                        param_grid, 
                        scoring='accuracy', 
                        cv=3,
                        n_jobs=-1)

 

pred_train = g_search.predict(X_train_scaled)
pred_test = g_search.predict(X_test_scaled)

print(accuracy_score(y_train, pred_train),  accuracy_score(y_test, pred_test))
0.9859154929577465,  0.972027972027972

 

교차검증

from sklearn.model_selection import cross_val_score
from sklearn.svm import SVC
from sklearn.preprocessing import MinMaxScaler
X_scaled = MinMaxScaler().fit_transform(X)
scores = cross_val_score(SVC(kernel='linear') , X_scaled , y , scoring='accuracy',cv=5)
scores
#==> array([0.96521739, 0.9826087 , 0.98230088, 0.96460177, 0.98230088])

iris DataSet으로 분류

  • 다중 클래스 분류
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
import numpy as np
import pandas as pd

iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y)

# scaler = StandardScaler()
scaler = MinMaxScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# svm = SVC(kernel='linear')
svm = SVC()
svm.fit(X_train_scaled, y_train)

pred_train = svm.predict(X_train_scaled)
pred_test = svm.predict(X_test_scaled)'

accuracy_score(y_train, pred_train), accuracy_score(y_test, pred_test)
# (0.9553571428571429, 0.9736842105263158)

 

728x90
반응형