bskyvision RSS 태그 관리 글쓰기 방명록
2020-07-14 09:00:33
728x90

오늘은 사이킷런에서 제공하는 SVM을 가지고 간단한 분류 문제를 해결하는 법에 대해 다루도록 하겠습니다. 저는 이에 필요한 절차를 아래와 같은 5단계로 나눠봤습니다. 

 

1. 데이터셋 불러오기

2. 데이터셋을 훈련셋과 테스트셋으로 분리

3. 특성 스케일링(feature scaling)

4. 훈련셋으로 SVM 훈련

5. 테스트셋을 가지고 성능 확인

 

자, 그럼 첫 단계부터 하나씩 시작해보겠습니다. 실습을 진행하기 위해서는 사이킷런과 넘파이 패키지가 필요하니 설치하지 않으신 분들은 설치해주시기 바랍니다. 또한 저는 구글 코랩 노트북에서 실습을 진행하는데, 다른 개발환경에서 실습을 진행하셔도 무방합니다. 

 

1. 데이터셋 불러오기

사이킷런에서는 아주 유명한 데이터셋 중에 하나인 붓꽃품종분류 데이터셋을 제공합니다. 저는 그것을 이용해서 실습을 진행하겠습니다. 먼저 데이터셋을 불러오겠습니다. 

 

1
2
3
from sklearn.datasets import load_iris
 
iris_dataset = load_iris() # 붓꽃 데이터셋을 적재합니다. 
cs

 

데이터셋이 어떻게 생겼는지 한번 구경해보겠습니다. 

 

1
print(iris_dataset)
cs

 

위 코드를 실행하시면 데이터셋에 대한 정보가 딕셔너리의 형태로 잘 담겨져 있다는 것을 확인하실 수 있습니다. 특성, 타겟(라벨), 특성 이름, 타겟 이름 등의 데이터가 담겨져 있습니다. 

 

 

2. 데이터셋을 훈련셋과 테스트셋으로 분리

이제 데이터셋을 훈련셋과 테스트셋으로 분리하도록 하겠습니다. 총 150개의 샘플이 있는데, 그중 80%인 120개를 훈련셋으로, 나머지 20% 30개를 테스트셋으로 사용하겠습니다. 

 

1
2
3
4
from sklearn.model_selection import train_test_split
 
X_train, X_test, y_train, y_test = train_test_split(iris_dataset['data'], iris_dataset['target'], test_size = 0.2)
# 데이터셋을 랜덤하게 80%의 훈련셋과 20%의 테스트셋으로 분리합니다.
cs

 

X_train에는 훈련셋의 특성들이 담겨 있고, X_test에는 테스트셋의 특성들이 담겨 있습니다. 또한 y_train에는 훈련셋의 타겟들이, y_test에는 테스트셋의 타겟들이 담겨 있습니다. X_train 안에 무엇이 들어 있는지 살펴보겠습니다. 

 

1
print(X_train)
cs

 

 

위 그림에 표시한대로 행(row)은 샘플을, 열(column)은 특성을 나타냅니다. 참고로 붓꽃품종 데이터셋에서 특성1은 꽃받침 길이(sepal length), 특성2는 꽃받침 너비(sepal width), 특성3은 꽃잎 길이(petal length), 특성4는 꽃잎 너비(petal width)입니다. 이 네가지 특성을 활용해서 붓꽃의 품종을 분류하겠다는 것이죠. 저 네가지 특성을 잘 살펴보면 붓꽃의 품종 분류가 가능한가 봅니다. 

 

이번에는 y_train 내부를 살펴보겠습니다. 

 

1
print(y_train)
cs

 

 

0, 1, 2의 숫자들로 이루어진 것을 확인할 수 있습니다. 여기서 0, 1, 2는 각각 setosa, versicolour, virginica라는 이름의 품종을 지칭합니다. 식물학자가 아닌 이상 알 필요 없으니 굳이 검색해보지 마세요.^^ 

 

3. 특성 스케일링(feature scaling)

SVM을 훈련하기 전에 특성을 전처리해줘야 합니다. 왜냐하면, 각 특성마다 값의 범위에 차이가 있기 때문입니다. 

 

1
2
3
4
print("특성1 범위: ""[", min(X_train[:, 0]), ",", max(X_train[:, 0]), "]")
print("특성2 범위: ""[", min(X_train[:, 1]), ",", max(X_train[:, 1]), "]")
print("특성3 범위: ""[", min(X_train[:, 2]), ",", max(X_train[:, 2]), "]")
print("특성4 범위: ""[", min(X_train[:, 3]), ",", max(X_train[:, 3]), "]")
cs

 

 

사실 붓꽃품종 데이터셋 내의 특성들의 경우에는 그 범위의 차이가 심하지 않지만, 일반적으로는 차이가 큽니다. 특성 간 값의 범위가 크면 머신러닝 모델을 제대로 훈련시킬 수 없습니다. 값의 범위가 큰 특성에 좌지우지될 가능성이 있기 때문입니다. 값의 범위가 크다고 더 의미있는 특성이 결코 아닙니다. 값의 범위는 작지만 그 안에 매우 의미있는 정보를 담고 있는 특성도 많습니다. 따라서 특성들을 스케일링해줘야 합니다. 특성 스케일링에 대해서는 이전 포스팅에서 자세히 다뤘으니 참고하시길 바랍니다. ☞ 정규화(normalization)와 표준화(standardization), 머신러닝 성능 향상을 위한 필수 단계

 

특성 스케일링이란 간단히 말해서 특성 값들을 비슷한 범위로 매핑해주는 것을 의미합니다. 널리 사용되는 방법에는 정규화(normalization)와 표준화(standardization)가 있는데, 여기서는 표준화 방법을 사용하겠습니다. 표준화라는 것은 각 특성이 정규분포를 따른다고 가정하고, 평균 0, 표준편차 1이 되도록 특성값들을 변환해주는 것을 의미합니다.

 

 

좀 더 구체적으로 말씀드리면, 훈련셋 특성의 평균 및 표준편차를 계산해서 그것을 가지고 훈련셋 특성과 테스트셋 특성의 값을 변환해줍니다. 다음 코드를 실행하시면 표준화된 특성을 얻을 수 있습니다. 

 

1
2
3
4
5
6
7
from sklearn.preprocessing import StandardScaler
 
sc = StandardScaler()
sc.fit(X_train)
 
X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)
cs

 

각 특성의 범위가 어떻게 변했는지 확인해보겠습니다. 

 

1
2
3
4
print("표준화된 특성1 범위: ""[", min(X_train_std[:, 0]), ",", max(X_train_std[:, 0]), "]")
print("표준화된 특성2 범위: ""[", min(X_train_std[:, 1]), ",", max(X_train_std[:, 1]), "]")
print("표준화된 특성3 범위: ""[", min(X_train_std[:, 2]), ",", max(X_train_std[:, 2]), "]")
print("표준화된 특성4 범위: ""[", min(X_train_std[:, 3]), ",", max(X_train_std[:, 3]), "]")
cs

 

 

특성들의 범위가 비슷해졌음을 확인하실 수 있습니다. 이제 드디어 SVM을 훈련할 준비가 되었습니다. 

 

4. 훈련셋으로 SVM 훈련

저는 훈련셋의 표준화된 특성과 그에 해당하는 라벨로 RBF 커널 SVM을 훈련시키도록 하겠습니다. 

 

1
2
3
4
5
from sklearn.svm import SVC
 
svm_model = SVC(kernel='rbf', C=8, gamma=0.1)
 
svm_model.fit(X_train_std, y_train) # SVM 분류 모델 훈련
cs

 

SVC라고 되어 있는데, 분류(classification)용 SVM을 SVC라고 부르기도 합니다. 

 

5. 테스트셋을 가지고 성능 확인

잘 훈련되었는지 테스트셋을 가지고 성능을 확인해보도록 하겠습니다. 

 

1
y_pred = svm_model.predict(X_test_std) # 테스트
cs

 

테스트셋의 라벨이 잘 예측되었는지, 예측된 라벨과 ground-truth 라벨을 각각 보여드리겠습니다. 

 

1
2
print("예측된 라벨:", y_pred)
print("ground-truth 라벨:", y_test)
cs

 

 

엇, 모든 요소가 같네요. 완벽하게 예측해냈습니다. 예측 정확도를 계산해보니 1.00, 즉 100%가 나오네요. 

 

1
print("prediction accuracy: {:.2f}".format(np.mean(y_pred == y_test))) # 예측 정확도
cs

 

 

전체 코드 정리 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import numpy as np
from sklearn.datasets import load_iris
 
iris_dataset = load_iris() # 붓꽃 데이터셋을 적재합니다. 
 
print(iris_dataset)
 
from sklearn.model_selection import train_test_split
 
X_train, X_test, y_train, y_test = train_test_split(iris_dataset['data'], iris_dataset['target'], test_size = 0.2)
# 데이터셋을 랜덤하게 80%의 훈련셋과 20%의 테스트셋으로 분리합니다.
 
print(X_train)
 
print(y_train)
 
print("특성1 범위: ""[", min(X_train[:, 0]), ",", max(X_train[:, 0]), "]")
print("특성2 범위: ""[", min(X_train[:, 1]), ",", max(X_train[:, 1]), "]")
print("특성3 범위: ""[", min(X_train[:, 2]), ",", max(X_train[:, 2]), "]")
print("특성4 범위: ""[", min(X_train[:, 3]), ",", max(X_train[:, 3]), "]")
 
from sklearn.preprocessing import StandardScaler
 
sc = StandardScaler()
sc.fit(X_train)
 
X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)
 
print("표준화된 특성1 범위: ""[", min(X_train_std[:, 0]), ",", max(X_train_std[:, 0]), "]")
print("표준화된 특성2 범위: ""[", min(X_train_std[:, 1]), ",", max(X_train_std[:, 1]), "]")
print("표준화된 특성3 범위: ""[", min(X_train_std[:, 2]), ",", max(X_train_std[:, 2]), "]")
print("표준화된 특성4 범위: ""[", min(X_train_std[:, 3]), ",", max(X_train_std[:, 3]), "]")
 
from sklearn.svm import SVC
 
svm_model = SVC(kernel='rbf', C=8, gamma=0.1)
 
svm_model.fit(X_train_std, y_train) # SVM 분류 모델 훈련
 
y_pred = svm_model.predict(X_test_std) # 테스트
 
print("예측된 라벨:", y_pred)
print("ground-truth 라벨:", y_test)
 
print("prediction accuracy: {:.2f}".format(np.mean(y_pred == y_test))) # 예측 정확도
 
cs

 

100%의 예측 정확도와 같이 좋은 성능을 보일 수 있었던 이유는 크게 4가지로 볼 수 있습니다.

 

1) 좋은 특성 사용

4개의 특성들이 품종에 대해 변별력이 좋은 특성들인 것으로 보입니다. 특성이 좋지 않으면 아무리 좋은 머신러닝 방법을 사용하더라도 답이 없습니다. 

 

2) 특성 스케일링 시행

이 예제의 경우는 필요도가 적을 수 있으나, 대부분의 경우에는 필수입니다. 성능에 매우 큰 영향을 미치니 간과해서는 안 됩니다. 

 

3) SVM사용

어지간한 문제는 머신러닝 알고리즘 중에 SVM이 잘 해결해냅니다. CNN과 같은 딥러닝 방법보다 나을 때도 많습니다. 

 

4) SVM 매개변수 값 최적으로 설정

몇번의 시도를 통해 좋은 결과를 내는 매개변수값들을 찾아냈습니다. 매개변수에 따라 성능이 크게 달라질 수 있으니, grid search를 통해 최적의 값들을 찾아내는 것이 필요합니다. 

 

성능이 잘 안나오는 경우에는 이상의 4가지를 점검해보는 것이 좋습니다. 

 

오늘은 SVM에 대해 다뤘지만, 어떤 머신러닝, 딥러닝 모델이든 훈련하고 테스트하는데 있어 이상의 절차를 따릅니다. 디테일에서 조금씩 차이는 있을 수 있지만, 큰 틀에서는 같을 것입니다. 끝까지 읽어주셔서 감사합니다. 질문과 토론은 항상 환영이니 댓글로 남겨주세요.^^ 

 

 

bskyvision의 추천글 ☞

서포트 벡터 머신(SVM)의 사용자로서 꼭 알아야할 것들-매개변수 C와 gamma

정규화(normalization)와 표준화(standardization), 머신러닝 성능 향상을 위한 필수 단계  

LIBSVM 활용하여 매트랩에서 SVM 사용하기

태그 : , , ,
댓글

방문해주신 모든 분들을 환영합니다.

* 글을 읽던 중에 궁금했던 부분은 질문해주세요.

* 칭찬, 지적, 의문, 격려, 감사표현 등을 남겨주세요.

* 최대한 답변 드리도록 노력하겠습니다.

* 욕설과 광고를 담은 댓글은 가차없이 삭제합니다.


  1. 따뜻한 아아@2020.10.15 17:43 ~$ 블로그 글이 정말 큰 도움이 되네요. 블로그 글대로 따라했는데 이해가 쏙쏙되는데요. 한가지 궁금한 점 있는데요.
    위 코드중에서..
    X_train, X_test, y_train, y_test = train_test_split(iris_dataset['data'], iris_dataset['target'], test_size = 0.2)

    이게 X_train, X_test, y_train, y_test 를 변수 선언하는게 맞나요? 위와 같이 입력했는데 바로 변수선언이 되는지 이해가 잘안가네요
    그리고 test_size=0.2라고만 입력햇는데 test size가 20% 반영되나요? test_size라는 변수지정이 없었는데요..

    아직 많이 초보라 기초적인 질문일지도 모르겟네요..
    다시한번 쉬운 설명의 볼르그글 정말 감사드립니다 [댓글주소]  [수정/삭제]  [답글작성]
    • BlogIcon bskyvision@2020.10.15 20:50 신고 ~$ [답글]: 질문 감사합니다 ^^ 우선 train_tesr_split 이란 함수의 반환값들이 X_train, X_test, y_train, y_test에 대입되면서 변수가 선언됩니다. 그리고 test_size=0.2라고만 입력해도 test size가 20%로 반영됩니다. 여기서 test_size 라는 것은 train_test_split 함수의 매개변수 중 하나라서 변수는 아닙니다^^ [댓글주소]  [수정/삭제]
  2. 옥샘@2021.01.28 16:29 ~$ 머신러닝을 하는 일에 적용 해보려고 책을 읽어보다가 상형문자 같은 svm rbf kernel 검색으로 블로그에 들어와 읽어보면서 정말 도움이 많이 됐습니다. 비전문가라 코딩을 하면서 이게 뭔소린가 싶었는데 배경에 대한 설명이 너무 훌륭합니다. 감사합니다. [댓글주소]  [수정/삭제]  [답글작성]
  3. BlogIcon 쩌리@2021.02.15 20:58 ~$ 정말 많은 도움이 되었습니다!! 감사합니다...!!

    그리고 질문이 있습니다. 문장을 positive, negative와 같이 분류하고자 한다면 해당 텍스트 말뭉치가 예시에서의 특성1,2,3,4 라고 보면 될까요..??

    그리고 SVM사용에 있어서 train 파일의 개수는 어느정도가 적당할까요???

    파이썬 공부한지 한달정도 되었지만,,, 지금 관련 연구를 진행 중인데 어려움이 많아서 질문합니다ㅠㅠㅜ 감사합니다! [댓글주소]  [수정/삭제]  [답글작성]
    • BlogIcon bskyvision@2021.02.15 21:12 신고 ~$ [답글]: 질문 감사드립니다.^^

      1) 문장을 positive, negative와 같이 분류하고자 한다면 해당 텍스트 말뭉치가 예시에서의 특성1,2,3,4 라고 보면 될까요..??

      답변: 네. 그렇게 보면 될 것 같습니다.

      2) SVM사용에 있어서 train 파일의 개수는 어느정도가 적당할까요???

      답변: 훈련 샘플이 적어도 100개는 있어야 될 것 같습니다. [댓글주소]  [수정/삭제]
  4. 초보자@2021.03.21 14:49 ~$ 안녕하세요 덕분에 공부를 하고 있습니다
    print("prediction accuracy: {:.2f}".format(np.mean(y_pred == y_test))) # 예측 정확도
    을 실행시키면 NameError: name 'np' is not defined 이라고 뜨는데
    해결방법 알려주실 수 있을까요?
    감사합니다 [댓글주소]  [수정/삭제]  [답글작성]
  5. pkj0421@2021.07.02 16:48 ~$ 안녕하세요 SVM 사용법 잘보고 배웠습니다.
    그런데 제가 적용해보려는 data에 적용시키려고 하니 좀 문제가 있더군요.
    Y 값이 지금 raw data(float)인데 이를 클래스로 나뉘어서 0, 1, 2 이런식으로 data를 바꿔야할 것 같습니다.
    그래서 위에 코드에 나온 StandardScaler()를 y_train에도 써봤는데
    "Reshape your data either using array.reshape(-1, 1) if your data has a single feature or array.reshape(1, -1) if it contains a single sample."라는 오류와 함께 아마 1열로 된 data라 문제가 발생한것 같습니다. 이를 해결할 방법이 있을까요? [댓글주소]  [수정/삭제]  [답글작성]
  6. 초보학생@2021.09.19 14:06 ~$ 안녕하세요 블로그 글 잘 보고 갑니다. 다름이 아니라 혹시 이 블로그에 소개 된 내용을 학교 주제 발표시간에 코드와 함께 소개하고 싶은데 가능할까요? 출처는 명확히 남기겠습니다! [댓글주소]  [수정/삭제]  [답글작성]
guest@이름 ~$
guest@패스워드 ~$
guest@홈페이지주소작성 ~$

guest@댓글작성 ~$




bskyvision. Designed by bskyvision.