서포트 벡터 머신 SVM

  • 선을 구성하는 매개변수를 조정해 요소의 구분선을 찾고 이를 기반으로 패턴을 인식
  • 주어진 데이터가 어느 카테고리에 속할지 판단하는 이전 선형 분류 모델

image.png

  • 서포트 벡터 : 데이터를 구분하는 선과 가장 가까운 포인트
  • 마진 : 선과 가장 가까운 양 옆 데이터와의 거리

image.png

  • 두 데이터를 정확히 구분하는 선을 찾고 해당 직선이 없다면 어느정도 outlier를 무시하고 최적의 구분선을 찾음

BMI 계산 예제

In [1]:
import random
In [2]:
# BMI를 계산해 결과를 반환하는 함수
def calc_bmi(h, w):
    bmi = w / (h/100) ** 2
    if bmi < 18.5: return "thin"
    if bmi < 25: return "normal"
    return "fat"

# 출력 파일 준비
fp = open("bmi.csv","w",encoding="utf-8")
fp.write("height,weight,label\r\n")

# 무작위 데이터 생성
cnt = {"thin":0, "normal":0, "fat":0}
for i in range(20000):
    h = random.randint(120,200)
    w = random.randint(35, 80)
    label = calc_bmi(h, w)
    cnt[label] += 1
    fp.write("{0},{1},{2}\r\n".format(h, w, label))
fp.close()
print("ok,", cnt)
ok, {'thin': 6423, 'normal': 5867, 'fat': 7710}

학습 및 테스트

In [3]:
from sklearn import svm, metrics
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import pandas as pd
In [4]:
# 1단계 - 키와 몸무게 데이터 읽기
tbl = pd.read_csv('bmi.csv')
tbl.head()
Out[4]:
height weight label
0 162 39 thin
1 195 58 thin
2 175 41 thin
3 145 45 normal
4 124 65 fat
In [5]:
# 2단계 - 칼럼을 잘라 정규화
label = tbl["label"]
w = tbl['weight'] / 100 # 최대 100kg이라 가정
h = tbl['height'] / 200 # 최대 200cm이라 가정
wh = pd.concat([w, h], axis = 1)
In [6]:
label.head()
Out[6]:
0      thin
1      thin
2      thin
3    normal
4       fat
Name: label, dtype: object
In [7]:
wh.head()
Out[7]:
weight height
0 0.39 0.810
1 0.58 0.975
2 0.41 0.875
3 0.45 0.725
4 0.65 0.620
In [8]:
# 3단계 - 전용 데이터와 테스트 데이터 분리
data_train, data_test, label_train, label_test = train_test_split(wh, label)
In [9]:
# 4단계 - 학습
clf = svm.SVC()
clf.fit(data_train, label_train)
Out[9]:
SVC()
In [10]:
# 5단계 - 데이터 예측
predict = clf.predict(data_test)
In [11]:
# 6단계 - 결과 테스트
ac_score = metrics.accuracy_score(label_test, predict)
cl_report = metrics.classification_report(label_test, predict)
print('정답률:', ac_score)
print('리포트:', cl_report)
정답률: 0.9954
리포트:               precision    recall  f1-score   support

         fat       1.00      0.99      1.00      1934
      normal       0.99      1.00      0.99      1517
        thin       1.00      0.99      1.00      1549

    accuracy                           1.00      5000
   macro avg       1.00      1.00      1.00      5000
weighted avg       1.00      1.00      1.00      5000

데이터 분포 확인(시각화)

In [12]:
import matplotlib.pyplot as plt
import pandas as pd
In [13]:
# pandas로 csv 파일 읽기
tbl = pd.read_csv('bmi.csv', index_col=2)

# 그래프 그리기
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)

# 임의의 색으로 칠하기
def scatter(lbl, color):
    b = tbl.loc[lbl]
    ax.scatter(b['weight'],b['height'], c=color, label=lbl)
scatter('fat', 'red')
scatter('normal', 'yellow')
scatter('thin', 'blue')
ax.legend()
plt.show()

LinearSVC()

  • 선형 커널에 특화되어 계산이 빠름
In [17]:
# 1단계 - 데이터 읽기
tbl = pd.read_csv('bmi.csv')

# 2단계 - 정규호ㅠㅏ
label = tbl['label']
w = tbl['weight'] / 100
h = tbl['height'] / 200
wh = pd.concat([w, h], axis=1)

# 3단계 - 학습 전용 데이터와 테스트 전용 데이터 분리
data_train, data_test, label_train, label_test = train_test_split(wh, label)

# 4단계 - 데이터 학습하기
clf = svm.LinearSVC()
clf.fit(data_train, label_train)

# 5단계 - 데이터 예측
predict = clf.predict(data_test)

# 6단계 - 결과 테스트
ac_score = metrics.accuracy_score(label_test, predict)
cl_report = metrics.classification_report(label_test, predict)
print('정답률:', ac_score)
print('리포트: \n', cl_report)
정답률: 0.9214
리포트: 
               precision    recall  f1-score   support

         fat       0.90      1.00      0.95      1911
      normal       1.00      0.73      0.85      1483
        thin       0.89      1.00      0.94      1606

    accuracy                           0.92      5000
   macro avg       0.93      0.91      0.91      5000
weighted avg       0.93      0.92      0.92      5000