본문 바로가기
Python 과 머신러닝/III. 머신러닝 모델

[Python 머신러닝] 6장. 분류 (Classification) (w/ scikit-learn)

by JoyfulS 2019. 10. 25.

 

 

scikit-learn이란?

- scikit-learn은 2007년 구글 썸머 코드에서 처음 구현됐으며 현재 파이썬으로 구현된 가장 유명한 기계 학습 오픈 소스 라이브러리

- 아나콘다에서 기본적으로 제공하는 라이브러리 중 하나

- 장점 : 라이브러리 외적으로는 scikit 스택을 사용하고 있기 때문에 다른 라이브러리와의 호환성이 좋다. 내적으로는 통일된 인터페이스를 가지고 있기 때문에 매우 간단하게 여러 기법을 적용할 수 있어 쉽고 빠르게 최상의 결과를 얻을 수 있다.

- 라이브러리의 구성은 크게 지도 학습, 비지도 학습, 모델 선택 및 평가, 데이터 변환으로 나눌 수 있다

- scikit-learn 사용자 가이드 :  http://scikit-learn.org/stable/user_guide.html

- 지도 학습에는 서포트 벡터 머신, 나이브 베이즈(Naïve Bayes), 결정 트리(Decision Tree)등이 있으며 비지도 학습에는 군집화, 이상치 검출 등이 있다.

- 모델 선택 및 평가에는 교차 검증(cross-validation), 파이프라인(pipeline)등 있으며 마지막으로 데이터 변환에는 속성 추출(Feature Extraction), 전처리(Preprocessing)등이 있다.

 

- 클래스별로 보자면, 각 기법들이 공통으로 가지고 있어야 하는 기본 BaseEstimator가 있으며 기법의 공통적인 부분을 모은 ClassifierMixin, RegressorMixin, ClusterMixin들이 있어 기법들은 각각의 기법의 클래스를 상속 받아 구현할 수 있다.

- 대부분의 클래스는 입력 데이터를 적합화하는 fit 메소드와 새로운 데이터를 예측하는 predict 메소드를 가지고 있다.

 

참고 자료 : https://github.com/brenden17/blog/blob/master/post/ms.scikit-learn.v.md

 

 

1. kNN : k-Nearest Neighbors

 - 알려진 범주로 알려지지 않은 범주 분류 (해석 용이)

 - 기존의 범주가 존재해야 함

 - 결측치(NA) 및 이상치 전처리 중요

 - 많은 특징을 갖는 데이터 셋은 부적합

 - 유클리드 거리 계산식 (Euclidean distance) 이용 : 가장 유사한 범주를 가장 가까운 거리를 통해 선택

 - 적용 분야 : 개인별 영화 추천, 이미지/비디오에서 얼굴 또는 글자 인식, 유전자 데이터 패턴 식별

 

2. NB : Naive Bayes

 - 통계적 분류기

 - 주어진 데이터가 특정 클래스에 속하는지를 확률을 통해서 예측  ( 조건부 확률 이용 - P(B|A) )

 - 베이즈 확률 정리(Bayes' theorem)을 적용한 기계학습 방법 (사전/사후 확률 사이의 관계를 나타낸 이론)

 - 특정 영역에서는 DT나 kNN 분류기보다 성능이 우수

 - 텍스트 데이터처럼 희소한 고차원인 경우 높은 정확도와 속도 제공

 - 적용 분야 : 스팸 메일 분류, 문서(주제) 분류, 비 유무 예측, 컴퓨터 네트워크 상 침입자 분류(악성코드 유무)

 

3. SVM : Support Vector Machine

 - SVM 알고리즘 : 가상의 직선을 중심으로 거리를 계산하여 최대의 직사각형 형태(Margin)로 영역을 넓힌다.

    즉 Margin을 최대로 만드는 알고리즘!

 [ Margin : 점에 닿기 전까지의 선형 분류기의 폭 ]  [ Support Vectors : Marging과 닿는 점들 ]

 - 이진분류 : 두 범주를 직선으로 분류 / 선형분리 - 2개의 집합을 직선으로 분리

 - kNN과 선형회귀 모델링 기법이 적용 => 분류와 수치 예측 가능

 - 비선형 분류를 위해서 데이터의 차원을 고차원으로 변경하여 직선으로 분리 (커널 트릭)

 - 커널 트릭(Kernel Trick) : 비선형(Non Linear)관계를 선형으로 변환하는 역할

 - 커털 트릭에 사용되는 '커널 함수' 종류 : linear(Gaussian), polynomial radial, sigmoid

   

다음의 그림들은 커널 트릭의 개념을 설명한다.

 - 다양한 데이터 셋에서 잘 동작하는 강력한 모델 (저차원, 고차원 데이터 모두에서 동작 잘됨)

 - 데이터의 특징이 적어도 복잡한 결정 경계 생성, 모든 특징과 스케일이 비슷한 경우에 유리함

 - 단, 데이터 전처리와 매개변수 설정에 주의 & 샘플(관측치)이 많은 경우 불리함 (100,000개 이상)

 - 모델 분석이 어려움(블랙박스화 - 예측과정 이해가 어려움)

 - 2000년대 초반에 많이 사용되는 분류 알고리즘

 - 적용 분야 : 바이오인포매틱스의 마이크로 유전자 데이터 분류, 인간의 얼굴/ 문자/ 숫자 인식

 - 이미지 데이터 패턴 인식에 적합

 

 


< 실습 내용 >

1. kNN

2. NB

3. SVM

4. npy파일 저장 및 불러오기

5. 스팸 메일 분류

 

1. kNN

import numpy as np # 다차원배열, 선형대수 연산 
import matplotlib.pyplot as plt

# 1. 알려진 두 집단 x,y 산점도 시각화 
plt.scatter(1.2, 1.1) # A 집단
plt.scatter(1.0, 1.0)
plt.scatter(1.8, 0.8) # B 집단 
plt.scatter(2, 0.9)

 

plt.scatter(1.6, 0.85, color='r') # 분류대상 

plt.show()

# 블럭실행

실행 결과
A집단, B집단, 분류대상


# 2. DATA 생성과 함수 정의 
p1 = [1.2, 1.1] # A 집단 
p2 = [1.0, 1.0]
p3 = [1.8, 0.8] # B 집단
p4 = [2, 0.9]
category = ['A','A','B','B'] # 알려진 집단 분류범주(Y변수)
p5 = [1.6, 0.85] # 분류대상 

p1 - p2 # 오류
# list로는 연산 불가능 -> 선형대수연산이 가능한 numpy의 array로 변경

# data 생성 함수 정의
def data_set():
    # 선형대수 연산 : numpy형 변환 
    know_group = np.array([p1, p2, p3, p4]) # 알려진 집단 
    not_know_group = np.array(p5) # 알려지지 않은 집단
    class_category = np.array(category) # 정답(분류범주)
    return know_group, not_know_group, class_category 


# 함수 호출 : dataset 생성
know, not_know, cate = data_set()
know
'''
array([[1.2, 1.1],
       [1. , 1. ],
       [1.8, 0.8],
       [2. , 0.9]])
'''
not_know # 분류대상
# array([1.6 , 0.85])


유클리드 거리계산식 : 차(-) -> 제곱 -> 합 -> 제곱근

diff = know - not_know # 차(-)
sq_diff = diff**2 # 제곱
sum_sq_diff = sq_diff.sum(axis = 1) # 행 단위 합계
distance = np.sqrt(sum_sq_diff) # 제곱근
distance
# [0.47169906, 0.61846584, 0.20615528, 0.40311289]
값이 가장 작은 것이 가장 가까운 거리를 의미


2. NB

from sklearn.datasets import load_iris # dataset
from sklearn.naive_bayes import GaussianNB # model 생성
from sklearn.model_selection import train_test_split # train/test set
from sklearn.metrics import accuracy_score, confusion_matrix # model 평가

# y변수 : 다항분류

# 1. data loading & 변수 생성
X, y = load_iris(return_X_y = True)

# 2. train/test split
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 123)
# 랜덤하게 샘플링하되 특정 번호를 지정함으로써 반복해서 시도하더라도 항상 같도록!

x_train.shape # (105, 4)
y_train.shape # (105,)


# 3. model
model = GaussianNB()
model.fit(X=x_train, y=y_train)


# 4. model 평가
y_pred = model.predict(x_test) # 예측치
y_true = y_test # 정답

# 분류정확도 - accuracy_score 함수 사용해서 구하기
acc = accuracy_score(y_true, y_pred)
acc # 0.9555555555555556

con_mat = confusion_matrix(y_true, y_pred)
con_mat
'''
array([[18,  0,  0],
       [ 0, 10,  0],
       [ 0,  2, 15]], dtype=int64)
'''
y_true[:10]  # [1, 2, 2, 1, 0, 2, 1, 0, 0, 1]
y_pred[:10]  # [1, 2, 2, 1, 0, 2, 1, 0, 0, 1]

type(con_mat) # numpy.ndarray
con_mat.shape # (3, 3)

# 분류정확도 - 식을 통해 구하기
acc = (con_mat[0,0] + con_mat[1,1] + con_mat[2,2]) / len(y_true)
acc # 0.9555555555555556

 

3. SVM

from sklearn.datasets import load_iris # dataset
from sklearn.svm import SVC # model 생성
from sklearn.model_selection import train_test_split # train/test set
from sklearn.metrics import accuracy_score, confusion_matrix # model 평가

# y변수 : 다항분류

# 1. data loading & 변수 생성
X, y = load_iris(return_X_y = True)

 


# 2. train/test split
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 123)
# 랜덤하게 샘플링하되 특정 번호를 지정함으로써 반복해서 시도하더라도 항상 같도록!

x_train.shape # (105, 4)
y_train.shape # (105,)

 


# 3. model
help(SVC)
model = SVC()  # kernel = 'rbf'  : default
# 데이터의 특징 때문에 분류정확도가 낮게 나오면 다른 커널 함수를 인수로 지정할 수 있음
'linear', 'poly', 'rbf', 'sigmoid' 등

 

model.fit(X=x_train, y=y_train)


# 4. model 평가
y_pred = model.predict(x_test) # 예측치
y_true = y_test # 정답

# 분류정확도 - accuracy_score 함수 사용해서 구하기
acc = accuracy_score(y_true, y_pred)
acc # 0.9777777777777777

con_mat = confusion_matrix(y_true, y_pred)
con_mat
'''
array([[18,  0,  0],
       [ 0, 10,  0],
       [ 0,  1, 16]], dtype=int64)
'''
y_true[:10]  # [1, 2, 2, 1, 0, 2, 1, 0, 0, 1]
y_pred[:10]  # [1, 2, 2, 1, 0, 1, 1, 0, 0, 1]

type(con_mat) # numpy.ndarray
con_mat.shape # (3, 3)

# 분류정확도 - 식을 통해 구하기
acc = (con_mat[0,0] + con_mat[1,1] + con_mat[2,2]) / len(y_true)
acc # 0.9777777777777777

## iris 데이터의 경우, NB모델보다 SVM모델을 사용할 때 분류정확도가 더 올라간 것을 확인할 수 있음

 

 

4. npy파일 저장 및 불러오기

# numpy dataset file save & load

import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

 


# 1. dataset load
X, y= load_iris(return_X_y=True)

X.shape # (150, 4)
type(X) # numpy.ndarray  (numpy의 array 형태)

 


# 2. train/test
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

type(x_train) # numpy.ndarray
x_train.shape # (105, 4)

# 3. numpy dataset file save
iris_train_test = (x_train, x_test, y_train, y_test)  # 하나의 변수에 데이터 담기!
np.save("../data/iris_train_test.npy", iris_train_test)  # 파일이름 원하는대로 지정
# 'allow_pickle = True'가 default

# 4. numpy dataset file load
x_train, x_test, y_train, y_test = np.load("../data/iris_train_test.npy", allow_pickle=True)
# 'allow_pickle=True' 로 저장했으면 가져올때도 같은 값으로 지정해서 불러와야함!
# True로 저장하고 False로 불러오려고 하면 오류발생

type(x_train) # numpy.ndarray
x_train.shape # (105, 4)

 

 

5. 스팸 메일 분류

import numpy as np  # np.load()
from sklearn.naive_bayes import GaussianNB
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score, confusion_matrix 

# 1. dataset loading

spam_train_test.zip
0.60MB

x_train, x_test, y_train, y_test = np.load(file="../data/spam_train_test.npy", allow_pickle=True)

x_train.shape # (4459, 4000)
x_test.shape  # (1115, 4000)

type(y_train) # list
type(y_test) # list

# list -> numpy
y_train = np.array(y_train)
y_test = np.array(y_test)

y_train.shape # (4459,)
y_test.shape # (1115,)

y_train[:10] # [0, 0, 0, 1, 0, 1, 0, 0, 0, 0]  => 1은 스팸메일

# 2. GaussianNB  vs  SVM
model = GaussianNB()
model.fit(X=x_train, y=y_train)

model2 = SVC(kernel='linear')
model2.fit(X=x_train, y=y_train)


# 3. model 평가

# 1) 예측치
y_pred = model.predict(X = x_test)
y_pred2 = model2.predict(X = x_test)
y_true = y_test

# 2) 분류정확도
acc1 = accuracy_score(y_true, y_pred)
acc2 = accuracy_score(y_true, y_pred2)

print('accuracy1 (NB) =', acc1)
print('accuracy2 (SVM) =', acc2)

# accuracy1 (NB) = 0.8905829596412556
# accuracy2 (SVM) = 0.979372197309417
## SVM의 분류정확도가 더 높음

con_mat1 = confusion_matrix(y_true, y_pred)
con_mat1
'''
array([[853, 102],
       [ 20, 140]], dtype=int64)
'''
con_mat2 = confusion_matrix(y_true, y_pred2)
con_mat2
'''
array([[952,   3],
       [ 20, 140]], dtype=int64)
'''

-------------------------------------------------- example --------------------------------------------------

exam01_NB.py
0.00MB
exam02_sms_spam_data.py
0.00MB
weatherAUS.csv
3.51MB
sms_spam_data.zip
0.39MB

댓글