ㅅㅇ

머신러닝 _ 07_ 지도학습 _ 최근접이웃 본문

AI_STUDY/머신러닝

머신러닝 _ 07_ 지도학습 _ 최근접이웃

SO__OS 2022. 7. 10. 00:05

플레이데이터 빅데이터캠프 공부 내용 _ 7/5

머신러닝 _ 07_ 지도학습 _ 최근접이웃

1. K-최근접 이웃 (K-Nearest Neighbors, KNN)

예측하려는 데이터와 input 데이터들 간의 거리를 측정해 

  가장 가까운 K개의 데이터셋의 레이블을 참조해 분류/예측한다.

 

- 분류(Classification)와 회귀(Regression) 를 모두 지원한다.

 

1) 학습시 단순히 input 데이터(train)들을 저장만 하며, 
    - 학습 할 게 없다. 단순히 저장만 하면 된다.


2) 예측 시점에 거리를 계산한다. 이때 들어온 새로운 데이터셋과 학습 데이터 간의 거리를 계산하는 것
    - 학습은 빠르지만,  예측시 시간이 많이 걸린다.

 

 

2. 분류 문제 에서의 KNN 예측 예시 설명

 

- 물음표는 무엇인지 추측하고자 한다.

 

 

 

- K-NN에서 K새로운 데이터포인트를 분류할때 확인할 데이터 포인트의 개수를 지정하는 하이퍼파라미터 가 있다.

 

 

- K를 1로 하면 파란색   = > overfitting

  K를 3으로 하면 주황색 으로 분류한다.

 


1) K가 너무 작으면 Overfitting (복잡)이 일어날 수 있다.  = >  K값을 더 크게 잡는다.

 

2)  K가 너무 크면 Underfitting (단순)이 발생할 수 있다.  = >  K값을 더 작게 잡는다.

     - 예측하려는 데이터와 거리가 먼 input 데이터까지 범위로 지정하게 됨.

 

3. 주요 하이퍼 파라미터

- sklearn.neighbors.KNeighborsClassifier 사용


1) 이웃 수 n_neighbors = K

    - K가 작을 수록 모델이 복잡해져 과대적합이 일어나고,

      너무 크면 단순해져 성능이 나빠지는 과소적합이 일어난다.


     - n_neighbors는 Feature  수의 제곱근 정도를 지정할 때 성능이 좋은 것으로 알려져 있다.

 


2) 거리 재는 방법  p = 


    - feature 가 몇 개이든(몇 차원이든)   같은 feature 끼리 아래처럼 연산해주면 됨.


    - p=2  유클리디안 거리(Euclidean distance - 기본값)
    - p=1: 맨하탄 거리(Manhattan distance)
    

  - 유클리디안 거리(Euclidean_distance)

 

  - 맨하탄 거리 (Manhattan distance)

 

 

< 요약 정리 >

  • K-NN은 이해하기 쉬운 모델이며 튜닝할 하이퍼파라미터의 수가 적어 빠르게 만들 수있다.
  • 계산을 추론할 때 하기에 이때 시간이 많이 걸림으로 서비스 운영할 때는 좋은 모델이 아니다.
  • K-NN은 서비스할 모델을 구현할때 보다는 복잡한 알고리즘을 적용해 보기 전에 확인용 또는 base line을 잡기 위한 모델로 사용한다. - 튜닝 전에 기준점 값 (우리가 튜닝하여 더 향상 시키는 작업에서 기준 base line 점)
  • 훈련세트가 너무 큰 경우(Feature나 관측치의 개수가 많은 경우) 거리를 계산하는 양이 늘어나 예측이 느려진다.
    • 추론에 시간이 많이 걸린다.
  • Feature간의 값의 단위가 다르면 작은 단위의 Feature에 영향을 많이 받게 되므로 전처리로 Feature Scaling작업이 필요하다.
  • Feature가 너무 많은 경우와 대부분의 값이 0으로 구성된(희소-sparse) 데이터셋에서 성능이 아주 나쁘다.

 

4. KNN 기본예제 - K 값 변화에 따른 성능 변화 확인

 

# 위스콘신 유방암 데이터를 이용한 암환자 분류 

from sklearn.datasets import load_breast_cancer

 

 

1) 데이터 셋 로드, train/test set 분리

import pandas as pd
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=1)

 

 

2) Feature scaling 전처리

 

- Feature간의 값의 단위가 다르면 작은 단위의 Feature에 영향을 많이 받게 되므로 해야하는 전처리.

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

 

 

3) 학습, 예측, 평가

 

  - 하이퍼 파라미터 k값 변화에 따른 accuracy의 변화 확인

   

    = >   k_params = range(1,11)     # 1 ~ 10

 

from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score

train_acc = []
test_acc = []

k_params = range(1,11) # 1 ~ 10
for k in k_params:
    # 모델 생성
    knn = KNeighborsClassifier(n_neighbors = k) # p = 2 : 기본값  유클리디안 거리
    
    # 학습
    knn.fit(X_train_scaled, y_train)

    #추론 및 평가
    pred_train = knn.predict(X_train_scaled)
    pred_test = knn.predict(X_test_scaled)
    
    #평가
    train_acc.append(accuracy_score(y_train, pred_train))
    test_acc.append(accuracy_score(y_test, pred_test))

 

 

4) accuracy 평가 결과 데이터 프레임과  그래프로 최적의 k 값 확인

 

  - 하이퍼 파라미터 k값 변화에 따른 accuracy의 변화 확인

          : k=1 에서 부터 커질 때 점차 단순한 모델이 되면서 train set의 성능은 점차 떨어지고

            test set은 overfitting에서 벗어나 성능이 좋아지다가 점차 단순한 모델이 되어가면서 유지되고 심하면 낮아짐.

 

df = pd.DataFrame({
    "K":k_params,
    "Train":train_acc,
    "Test": test_acc   
})
df.set_index('K', inplace=True)

df

 

- 현재 test set 성능을 보면 좋은 편이기에 

   train 과 test 셋 의 성능 차이가 가장 적게 나는 k  = 8  가 최적의 하이퍼파라미터라 생각 된다.

import matplotlib.pyplot as plt
df.plot(figsize=(8,6))
plt.show()

# 가장 성능 차이가 적게 나는 k = 8 정도가 좋을 듯 하다.

 

5) 최종 평가

best_model = KNeighborsClassifier(n_neighbors=8)
best_model.fit(X_train_scaled, y_train)
#예측
pred_train = best_model.predict(X_train_scaled)
pred_test = best_model.predict(X_test_scaled)
#평가
print('Train 정확도: ',accuracy_score(y_train, pred_train))
print('Test 정확도: ',accuracy_score(y_test, pred_test))
Train 정확도:  0.9741784037558685
Test 정확도:  0.972027972027972

 

5. GridSearch/Pipline 을 이용해 구현

- Pipeline을 이용해   == > 전처리기와 모델을 연결한다.
- GridSearchCV를 이용해   == > 최적의 하이퍼파라미터를 검색한다.

 

 

1) 데이터 셋 로드 및 train/test set 나누기

 

from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score, classification_report

X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X,y, stratify=y, random_state=0)

 

 

2) Pipeline / GridSearchCV 생성 및 학습

 

# pipeline
order = [
    ('scaler', StandardScaler()),
    ('knn', KNeighborsClassifier())
]
pipeline = Pipeline(order, verbose=True)

# gridsearchCV
param = {
    "knn__n_neighbors":range(1,11), # k 
    "knn__p":[1,2] # 거리재는 방식 
}
gs = GridSearchCV(pipeline, param, scoring='accuracy', cv=5, n_jobs=-1)

gs.fit(X_train, y_train)

 

 

3) 결과 확인

result_df = pd.DataFrame(gs.cv_results_)
result_df[result_df.columns[6:]].sort_values('rank_test_score').head()

 

gs.best_params_
{'knn__n_neighbors': 3, 'knn__p': 1}
 
 

4) 최종평가

pred_test = gs.predict(X_test)
accuracy_score(y_test, pred_test)
0.958041958041958
 
 
print(classification_report(y_test, pred_test))
              precision    recall  f1-score   support

           0       0.98      0.91      0.94        53
           1       0.95      0.99      0.97        90

    accuracy                           0.96       143
   macro avg       0.96      0.95      0.95       143
weighted avg       0.96      0.96      0.96       143