이전 글에서 로지스틱 회귀를 통한 분류 문제 해결 방법을 설명했으며, 이번에는 더 강력한 분류 모델인 SVM을 탐구합니다. 이 글은 코드 중심의 실습 위주로 구성되어 데이터 처리 기술이 점점 다양해지는 과정을 경험할 수 있습니다.
SVM은 중소 규모의 복잡한 데이터 세트 분류에 특화된 인기 있는 머신러닝 모델입니다.
一、SVM의 기본 개념
SVM은 여러 데이터 포인트 중 최적의 분류 경계를 찾는 알고리즘입니다. 이 경계에 위치한 데이터 포인트를 '지원 벡터'라고 하며, 이들이 분리 초평면을 지지하기 때문에 이름이 붙었습니다.
최적 경계를 어떻게 판단할까요? 위 그림에서 세 개의 검은색 직선이 데이터를 완벽히 분리하는 것을 확인할 수 있습니다. 이 경우 단일 직선으로 무수한 해를 얻을 수 있습니다. 그렇다면 어떤 직선이 최적일까요?
위 그림에서 분류된 데이터 포인트까지의 거리를 계산해 보면, 데이터와의 거리를 최대화하는 직선이 유일한 해가 됩니다. 허용 오차 구간을 최대화하는 것이 목표이며, 이 구간 내에 위치한 데이터 포인트가 지원 벡터입니다.
이러한 원리를 바탕으로 SVM이 작동합니다.
二、코드를 통한 이론 적용
2.1 데이터 로드 및 준비
필요한 라이브러리 불러오기:
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
데이터 세트 로드(링크는 중요하지 않음):
data = pd.read_csv('https://blog.caiyongji.com/assets/mouse_viral_study.csv')
data.head()
| Med_1_mL | Med_2_mL | Virus Present | |
|---|---|---|---|
| 0 | 6.50823 | 8.58253 | 0 |
| 1 | 4.12612 | 3.07346 | 1 |
| 2 | 6.42787 | 6.36976 | 0 |
| 3 | 3.67295 | 4.90522 | 1 |
| 4 | 1.58032 | 2.44056 | 1 |
이 데이터 세트는 바이러스 감염 실험 결과를 시뮬레이션합니다. 두 가지 약물의 용량을 변화시켜 감염 여부를 관찰한 연구입니다.
- 특성: 약물 1의 용량(Med_1_mL), 약물 2의 용량(Med_2_mL)
- 레이블: 바이러스 감염 여부(1: 감염, 0: 비감염)
2.2 데이터 탐색
sns.scatterplot(x='Med_1_mL',y='Med_2_mL',hue='Virus Present',data=data)
Seaborn을 사용해 약물 용량과 감염 결과의 산포도를 시각화합니다.
sns.pairplot(data,hue='Virus Present')
특성 간 상관관계를 파악하기 위해 쌍별 그래프를 작성합니다.
약물 용량 증가가 감염 예방에 긍정적인 영향을 미친다는 결론을 도출할 수 있습니다.
2.3 SVM 모델 훈련
# SVC: Support Vector Classifier
from sklearn.svm import SVC
# 데이터 준비
labels = data['Virus Present']
features = data.drop('Virus Present',axis=1)
# 모델 정의
classifier = SVC(kernel='linear', C=1000)
# 모델 훈련
classifier.fit(features, labels)
# 경계선 시각화 함수 정의
def visualize_svm_model(model,features,labels):
features = features.values
labels = labels.values
# 산포도 출력
plt.scatter(features[:, 0], features[:, 1], c=labels, s=30,cmap='coolwarm')
# 결정 함수 시각화
ax = plt.gca()
xlim = ax.get_xlim()
ylim = ax.get_ylim()
# 격자 생성
xx = np.linspace(xlim[0], xlim[1], 30)
yy = np.linspace(ylim[0], ylim[1], 30)
YY, XX = np.meshgrid(yy, xx)
xy = np.vstack([XX.ravel(), YY.ravel()]).T
Z = model.decision_function(xy).reshape(XX.shape)
# 경계선 및 마진 시각화
ax.contour(XX, YY, Z, colors='k', levels=[-1, 0, 1], alpha=0.5,
linestyles=['--', '-', '--'])
# 지원 벡터 표시
ax.scatter(model.support_vectors_[:, 0], model.support_vectors_[:, 1], s=100,
linewidth=1, facecolors='none', edgecolors='k')
plt.show()
visualize_svm_model(classifier,features,labels)
sklearn의 SVC 분류기를 사용해 모델을 구현합니다.
2.4 C 매개변수 조정
C 매개변수는 L2 정규화 강도를 제어합니다. C 값이 클수록 정규화가 약해집니다.
classifier = SVC(kernel='linear', C=0.05)
classifier.fit(features, labels)
visualize_svm_model(classifier,features,labels)
C 값을 감소시키면 모델이 데이터에 적응하는 정도가 줄어듭니다.
2.5 커널 함수 선택
kernel 매개변수는 {'linear', 'poly', 'rbf', 'sigmoid', 'precomputed'} 중 선택 가능합니다. 선형 분류에 사용된 linear를 기준으로 비선형 분류 방법을 탐구합니다.
2.5.1 다항식 커널
다항식 커널(kernel='poly')은 단일 특성을 다중 특성으로 확장해 곡선을 근사합니다. 예를 들어, 특성 확장을 다음과 같이 수행할 수 있습니다:
| X | X^2 | X^3 | y | |
|---|---|---|---|---|
| 0 | 6.50823 | 6.50823² | 6.50823³ | 0 |
| 1 | 4.12612 | 4.12612² | 4.12612³ | 1 |
| 2 | 6.42787 | 6.42787² | 6.42787³ | 0 |
| 3 | 3.67295 | 3.67295² | 3.67295³ | 1 |
| 4 | 1.58032 | 1.58032² | 1.58032³ | 1 |
classifier = SVC(kernel='poly', C=0.05,degree=5)
classifier.fit(features, labels)
visualize_svm_model(classifier,features,labels)
다항식 커널을 사용하고 degree=5로 최고 차수를 설정합니다. 분류 경계가 곡선 형태로 나타납니다.
2.5.2 가우시안 RBF 커널
기본 커널은 가우시안 RBF입니다. gamma 매개변수는 커널의 모양을 조절합니다. gamma 값을 증가시키면 커널이 좁아져 각 데이터 포인트의 영향 범위가 줄어듭니다. 반대로 gamma 값을 감소시키면 커널이 넓어져 영향 범위가 확대됩니다.
classifier = SVC(kernel='rbf', C=1,gamma=0.01)
classifier.fit(features, labels)
visualize_svm_model(classifier,features,labels)
2.6 하이퍼파라미터 튜닝: 격자 탐색
from sklearn.model_selection import GridSearchCV
model = SVC()
param_grid = {'C':[0.01,0.1,1],'kernel':['rbf','poly','linear','sigmoid'],'gamma':[0.01,0.1,1]}
grid = GridSearchCV(model,param_grid)
grid.fit(features,labels)
print("최적 파라미터 =",grid.best_params_,"최고 점수 =",grid.best_score_)
GridSearchCV를 사용해 하이퍼파라미터 조합을 탐색해 최적 값을 찾습니다. 이 방법은 계산 자원을 활용한 강력한 튜닝 기법입니다. 그러나 파라미터 범위를 사전에 정의해야 합니다.
데이터 세트가 간단한 경우, 첫 번째 조합에서 100% 정확도를 달성할 수 있습니다. 출력 결과는 다음과 같습니다:
최적 파라미터 = {'C': 0.01, 'gamma': 0.01, 'kernel': 'rbf'}, 최고 점수 = 1.0
요약
선형 분리 가능한 데이터 세트에는 SVC(kernel='linear')를 사용할 수 있으며, 데이터량이 많거나 특성 수가 많은 경우 LinearSVC를 대체로 활용할 수 있습니다. 비선형 분류에는 가우시안 RBF, 다항식, 시그모이드 커널을 사용해 모델을 구축할 수 있습니다. GridSearchCV를 활용해 최적 파라미터를 탐색할 수 있습니다.
관련 글:
- 머신러닝(3): 로지스틱 회귀 이해 및 이진/다중 분류 코드 실습
- 머신러닝(2): 선형 회귀와 경사 하강법 이해 및 간단한 예측
- 머신러닝(1): 5분 안에 머신러닝 이해 및 실습 시작
- 사전 머신러닝(5): Matplotlib 기본 사용법 30분 정리
- 사전 머신러닝(4): Pandas 사용법 총체적 정리
- 사전 머신러닝(3): NumPy 기본 사용법 30분 정리
- 사전 머신러닝(2): Jupyter Notebook 기본 사용법 30분 정리
- 사전 머신러닝(1): 수학 기호 및 그리스 문자