외로운 Nova의 작업실

지도학습 - SVM 서포트 벡터 머신 이론 및 실습 본문

AI/machine-learning

지도학습 - SVM 서포트 벡터 머신 이론 및 실습

Nova_ 2023. 10. 8. 19:37

- 이론

 

서포트 벡터 머신 : 서포트 벡터를 기반으로 결정 경계선을 정하여 예측하는 알고리즘입니다.

쉬운설명 : 강북의 한남, 강남의 이태원을 기준으로 한강의 위치를 찾아 나중에 들어오는 위치로 강남과 강북을 예측하는 알고리즘

 

<서포트 벡터 머신의 용어>

위 사진에서 한남과 압구정은 서포트 벡터이고 그 사이 경계선을 결정 경계선이라 하고, 그 사이의 거리를 마진이라곻바니다. 이 결정 경계선을 어떻게 정할 것 인지가 SVM의 핵심입니다.

 

<COST>

결정 경계선을 후보 1처럼 둘 수있는데, 이때 학습 에러율은 높지만 마진이 커서 예측 성공률이 올라갑니다.

결정 경계선을 후보 2처럼 둘 수 있는데, 이때 학습 에러율은 적지만 마진이 작아서 예측 성공률이 떨어집니다.

따라서 이러한 학습 에러율과 마진을 컨트롤 하기위해 COST라는 변수를 만들었습니다.

 

COST : 비용이 낮으면 마진을 최대화여 학습 에러율을 높이고, 비용이 높으면 마진을 최소화하여 학습에러율을 낮춥니다.

 

<커널 트릭, 감마>

SVM의 결정 경계선을 직선이 아닌 곡선을 만들어주기위해 커널 트릭이라는 방법을 사용합니다. 만약 아래처럼 분류데이터가 나누어진다면 어떻게해야할까요?

이럴때 사용하는 방법이 커널트릭 방법입니다. 커널트릭을 이용해 2차원 공간의 데이터를 3차원 벡터공간으로 옮겨서 결정 경계를 찾습니다.

결국 2차원 평면상에는 곡선만이 남을 것 입니다.

이렇게 곡선의 비율을 조정하기 위해 감마라는 조절 변수를 사용합니다. 값이 작을 수록 직선이되며 클수록 곡선에 가까워집니다.

 

- 실습

 

<최적의 cost와 gamma찾기>

GridSearchCV 함수를 이용해서 각각 cost와 gamma후보군을 이용해 최적의 값을 추출해보겠습니다.

from sklearn.model_selection import GridSearchCV
from sklearn.metrics import classification_report
from sklearn.metrics import accuracy_score
from sklearn.svm import SVC  
import numpy as np

import pandas as pd
df = pd.read_csv("../data/csv/basketball_stat.csv")

from sklearn.model_selection import train_test_split
train, test = train_test_split(df, test_size=0.2)

def svc_param_selection(X, y, nfolds):
    
    svm_parameters = [
        {'kernel':['rbf'],
        'gamma':[0.00001, 0.0001, 0.001, 0.01, 0.1, 1],
        'C' : [0.01, 0.1, 1, 10, 100, 1000]
        }]
    
    clf = GridSearchCV(SVC(), svm_parameters, cv=10)
    clf.fit(X_train, y_train.values.ravel())
    print(clf.best_params_)
    
    return clf

X_train = train[['3P', 'BLK']]
y_train = train[['Pos']]

clf = svc_param_selection(X_train, y_train.values.ravel(), 10)

그 결과는 아래와 같습니다.

cost는 0.1 gamma는 1일때 가장 최적의 결정 경계선을 가진다고합니다. 

 

<결정 경계선 시각화>

어떻게 그 값이 최적인지 간단히 시각화를 통해 봐보겠습니다.

import pickle
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

# 시각화를 하기 위해, 최적의 C와 최적의 C를 비교하기 위한 다른 C를 후보로 저장합니다.
C_canditates = []
C_canditates.append(clf.best_params_['C'] * 0.01)
C_canditates.append(clf.best_params_['C'])
C_canditates.append(clf.best_params_['C'] * 100)

# 시각화를 하기 위해, 최적의 gamma와 최적의 gamma를 비교하기 위한 다른 gamma를 후보로 저장합니다.
gamma_candidates = []
gamma_candidates.append(clf.best_params_['gamma'] * 0.01)
gamma_candidates.append(clf.best_params_['gamma'])
gamma_candidates.append(clf.best_params_['gamma'] * 100)

X = train[['3P', 'BLK']]
Y = train['Pos'].tolist()

# 포지션에 해당하는 문자열 SG와 C를 벡터화합니다.
position = []
for gt in Y:
    if gt == 'C':
        position.append(0)
    else:
        position.append(1)

# 각각의 파라미터에 해당하는 SVM 모델을 만들어 classifiers에 저장합니다.
classifiers = []
for C in C_canditates:
    for gamma in gamma_candidates:
        clf = SVC(C=C, gamma=gamma)
        clf.fit(X, Y)
        classifiers.append((C, gamma, clf))

# 18,18 사이즈의 챠트를 구성합니다.
plt.figure(figsize=(18, 18))
xx, yy = np.meshgrid(np.linspace(0, 4, 100), np.linspace(0, 4, 100))

# 각각의 모델들에 대한 결정 경계 함수를 적용하여 함께 시각화합니다.
for (k, (C, gamma, clf)) in enumerate(classifiers):
    Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)

    # 최적의 모델을 포함한 다른 파라미터로 학습된 모델들을 함께 시각화해봅니다.
    plt.subplot(len(C_canditates), len(gamma_candidates), k + 1)
    plt.title("gamma=10^%d, C=10^%d" % (np.log10(gamma), np.log10(C)),
              size='medium')

    # 서포트 벡터와 결정경계선을 시각화합니다.
    plt.pcolormesh(xx, yy, -Z, cmap=plt.cm.RdBu)
    plt.scatter(X['3P'], X['BLK'], c=position, cmap=plt.cm.RdBu_r, edgecolors='k')

이 결과는 아래와 같습니다.

가운데 값이 가장 최적의 c와 gamma 값입니다. 

 

<실제 테스트>

최적의 C와 gamma값으로 모델을 테스트해보겠습니다.

# 테스트에 사용될 특징을 지정합니다
X_test = test[['3P', 'BLK']]

# 특징으로 예측할 값 (농구선수 포지션)을 지정합니다
y_test = test[['Pos']]

# 최적의 파라미터로 완성된 SVM에 테스트 데이터를 주입하여, 실제값과 예측값을 얻습니다.
y_true, y_pred = y_test, clf.predict(X_test)

print(classification_report(y_true, y_pred))
print()
print("accuracy : "+ str(accuracy_score(y_true, y_pred)) )

테스트 데이터에대한 예측 정확도가 0.8이 나왔습니다. 

 

실제 어떤 데이터가 틀렷는지 봐보겠습니다.

# 실제값(ground truth)과 예측값(prediction)이 어느 정도 일치하는 눈으로 직접 비교해봅니다
comparison = pd.DataFrame({'prediction':y_pred, 'ground_truth':y_true.values.ravel()}) 
comparison

0번 12번 14번등에서 오차가 있는 것을 확인할 수 있습니다.

 

'AI > machine-learning' 카테고리의 다른 글

앙상블 기법  (0) 2023.11.03
지도 학습 - 나이브 베이즈  (0) 2023.11.02
지도 학습 - 의사결정 트리  (1) 2023.10.31
지도 학습 - knn 알고리즘 이론 및 실습  (1) 2023.10.07
머신러닝 용어 정리  (1) 2023.10.07
Comments