본문 바로가기

대외활동/ABC 지역주도형 청년 취업역량강화 ESG 지원산업

[ABC 220921] 지도 학습 알고리즘 k-NN 알고리즘

반응형

지도 학습 알고리즘

  • 머신 러닝 알고리즘의 작동 방식 학습
    • 데이터로부터 어떻게 학습하고 예측하는가?
    • 모델의 복잡도가 어떤 역할을 하는가?
    • 알고리즘이 모델을 어떻게 만드는가?
    • 모델들의 장단점을 평가하고 어떤 데이터가 잘 들어맞을지 살펴보기
    • 매개변수와 옵션의 의미 학습
  • 예제에 사용할 데이터 셋
  • k-최근접 이웃
  • 선형모델
  • 결정트리
  • 결정트리의 앙상블

 

지도 학습 알고리즘 - 예제에 사용할 데이터셋

  • 예제에 사용할 데이터셋
    • 여러 알고리즘을 설명하기 위해 데이터셋도 여러개 사용 → 데이터 이해가 가장 중요하다
      • 어떤 데이터셋은 작고 인위적으로 만드는 것
      • 알고리즘의 특징을 부각하기 위해 만드는 것, 실제 샘플로 만든 큰 데이터 셋 등
    • 두 개의 특성을 가진 forge

 

지도 학습 알고리즘 - k-최근접 이웃

  • k-NN (k-nearest neighbors) 알고리즘은 가장 간단한 머신러닝 알고리즘
    • 훈련 데이터셋을 그냥 저장하는 것이 모델을 만드는 과정의 전부
    • 새로운 데이터 포인트에 대해 예측할 때 훈련 데이터 셋에서 가장 가까운 데이터 포인트 즉, "최근접 이웃"을 찾음
  • k-최근접 이웃 분류
    • 훈련 데이터 셋에서 가장 가까운 데이터 포인트를 찾음 → k-최근접 이웃
    • 가장 간단한 k-NN 알고리즘은 가장 가까운 훈련 데이터 포인트 하나를 최근접 이웃으로 찾아 예측에 사용

 

scikit-learn을 사용해서 k-최근접 이웃 알고리즘 구현 - 분류

  • KNeighborsClassifier 분석
    • 알고리즘이 클래스 0과 클래스 1로 지정한 영역으로 나뉘는 결정경계 (decision boundary) 확인 가능
    • 이웃을 하나 선택했을 때는 결정경계가 훈련 데이터에 가깝게 따라 가고 있음
    • 이웃의 수를 늘릴수록 결정 경계는 더 부드러워짐
    • 부드러운 경계는 더 단순한 모델을 의미
      • 이웃을 적게 사용하면 모델 복잡도
    • 유방암 데이터 셋을 이용해서 이웃의 수(결정 경계)에 따른 성능 평가
      • 모델의 복잡도와 일반화 사이의 관계 확인을 위해 유방암 데이터셋을 사용하여 성능 평가
      • 데이터 셋 분리(훈련 셋, 테스트 셋)
        • → KNeighborsClassifier 메소드 1에서 10까지 n_neighbors를 적용하여 모델 생성
        • → 훈련 세트 정확도 저장, 테스트 세트(일반화) 정확도 저장 → 정확도 그래프 비교
    • KNeighborsClassifier 타이타닉 생존자 예측에 따른 성능평가
      • Seaborn 에서 제공하는 titanic 데이터 셋 사용
      • 타이타닉 데이터 전처리(원 핫 인코딩 - 범주형 데이터를 모형이 인식할 수 있도록 숫자형으로 변환)
      • 데이터 셋 분리 (훈련 셋, 테스트 셋)

지도 학습 알고리즘 _ KNN 구현

mglearn 라이브러리 설치

pip install mglearn

한글 깨짐 방지

# 한글폰트 패치
import matplotlib as mpl
import matplotlib.pyplot as plt
 
%config InlineBackend.figure_format = 'retina'
 
!apt -qq -y install fonts-nanum
 
import matplotlib.font_manager as fm
fontpath = '/usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf'
font = fm.FontProperties(fname=fontpath, size=9)
plt.rc('font', family='NanumBarunGothic') 
mpl.font_manager._rebuild()

k-최근접 이웃 알고리즘 → 분류, 회귀 모델 모두 제공

훈련 데이터 셋에서 가장 가까운 데이터 포인트를 찾음 → 끼리끼리, 유유상종

 

forge 데이터셋 분류 예) 1-최근접

import mglearn
import matplotlib.pyplot as plt

import warnings
warnings.filterwarnings('ignore')

plt.figure(dpi=100)
mglearn.plots.plot_knn_classification(n_neighbors=1)

forge 데이터셋 분류 예) 3-최근접

plt.figure(dpi=100)
mglearn.plots.plot_knn_classification(n_neighbors=3)

분류 문제 정의 : forge 데이터셋을 사용한 이진 분류 문제 정의

 

데이터 준비하기

X, y = mglearn.datasets.make_forge() # X : 데이터(feature, 특성, 문제집), y : 레이블(label, 정답)

일반화 성능을 평가할 수 있도록 데이터 분리 → 훈련셋, 테스트셋

from sklearn.model_selection import train_test_split

X_train ,  X_test, y_train, y_test = train_test_split(X, y, random_state=7) # 75, 25비율로 나눠진다(default값)
X_train.shape # 26개 중 19개

X_test.shape # 26개 중 7개

k-최근접 이웃 분류 모델 설정

from sklearn.neighbors import KNeighborsClassifier

clf = KNeighborsClassifier(n_neighbors=3)

모델 학습하기

clf.fit(X_train, y_train )

score() 함수를 사용하여 예측 정확도 확인

clf.score(X_test, y_test)

clf.score(X_train, y_train)
# 훈련때는 94더니 test는 85? ==> overfitting 되고 있는 상황이다!

KNeigborsClssifier 이웃의 수에 따른 성능 평가

  1. 이웃의 수를 1 ~ 10까지 증가시켜서 학습 진행
  2. score() 함수를 이용하여 예측 정확도 저장
  3. 차트로 최적점 찾기
# 이웃의 수에 따른 정확도를 저장할 리스트 변수
train_scores = []
test_scores = []

n_neighbors_settings = range(1,15)

# 1~10까지 n_neighbors의 수를 증가시켜서 학습 후 정확도 저장
for n_neighbor in n_neighbors_settings :
  # 모델 생성 및 학습
  clf = KNeighborsClassifier(n_neighbors=n_neighbor)
  clf.fit(X_train, y_train)

  # 훈련 세트 정확도 저장
  train_scores.append(clf.score(X_train, y_train))

  # 테스트 세트 정확도 저장
  test_scores.append(clf.score(X_test, y_test))

#예측 정확도 비교 그래프 그리기
plt.figure(dpi=100)

plt.plot(n_neighbors_settings, train_scores, label='훈련 정확도')
plt.plot(n_neighbors_settings, test_scores, label='테스트 정확도')
plt.ylabel('정확도')
plt.xlabel('이웃의 수')
plt.legend()
plt.show()

유방암 데이터셋을 사용하여 이웃의 수 (결정경계)에 따른 성능 평가

데이터 준비하기

from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()

데이터 분리하기

from sklearn.model_selection import train_test_split

X_train , X_test , y_train , y_test = train_test_split(cancer.data, cancer.target, random_state=7)
cancer.data.shape

X_train.shape

X_test.shape

# 이웃의 수에 따른 정확도를 저장할 리스트 변수
train_scores = []
test_scores = []

n_neighbors_settings = range(1,21)

# 1~10까지 n_neighbors의 수를 증가시켜서 학습 후 정확도 저장
for n_neighbor in n_neighbors_settings :
  # 모델 생성 및 학습
  clf = KNeighborsClassifier(n_neighbors=n_neighbor)
  clf.fit(X_train, y_train)

  # 훈련 세트 정확도 저장
  train_scores.append(clf.score(X_train, y_train))

  # 테스트 세트 정확도 저장
  test_scores.append(clf.score(X_test, y_test))

#예측 정확도 비교 그래프 그리기
plt.figure(dpi=100)

plt.plot(n_neighbors_settings, train_scores, label='훈련 정확도')
plt.plot(n_neighbors_settings, test_scores, label='테스트 정확도')
plt.ylabel('정확도')
plt.xlabel('이웃의 수')
plt.legend()
plt.show()

지도 학습 알고리즘 k-최근접 이웃 알고리즘 정리

- 사이킷 런을 이용해서 k-최근접 이웃 알고리즘 구현

  • 장단점과 매개변수
    • 일반적으로 KNeighbors 분류기에 중요한 매개변수 : 데이터 포인트 사이의 거리를 재는 방법, 이웃의 수
      • 실제로 이웃의 수는 3개나 5개 정도로 적을 때 잘 작동하지만, 이 매개변수는 잘 조정해야함
    • KNN 장점
      • 이해하기 매우 쉬는 모델
      • 많이 조정하지 않아도 자주 좋은 성능을 발휘 더 복잡한 알고리즘을 적용해보기 전에 시도해볼 수 있는 좋은 시작점
    • KNN 단점
      • 보통 최근접 이웃 모델은 매우 빠르게 만들 수 있지만, 훈련세트가 매우 크면 예측이 느려짐
      • KNN 알고리즘을 사용할 땐 데이터를 전처리하는 과정이 필요
      • (수백개 이상의) 많은 특성을 가진 데이터셋에는 잘 동작하지 않음
      • 특성 값 대부분인 0 (즉, 희소한) 데이터 셋과는 특히 잘 작동하지 않음
    • 최근접 이웃 알고리즘이 이해하기 쉽지만, 예측이 느리고 많은 특성을 처리하는 능력이 부족해 현업에서는 잘 쓰지 않음
    • 이런 단점이 없는 알고리즘 ? → 선형 모델

KNeighborsClassifier 타이타닉 생존자 예측

문제 정의 : KNeighborClassfier 타이타닉 생존자 예측

생존자(1), 사망자(0) 예측

 

한글 깨짐 방지 코드

import matplotlib as mpl
import matplotlib.pyplot as plt
 
%config InlineBackend.figure_format = 'retina'
 
!apt -qq -y install fonts-nanum
 
import matplotlib.font_manager as fm
fontpath = '/usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf'
font = fm.FontProperties(fname=fontpath, size=9)
plt.rc('font', family='NanumBarunGothic') 
mpl.font_manager._rebuild()

데이터 준비하기

import pandas as pd
import seaborn as sns

df = sns.load_dataset('titanic')
df

데이터 탐색 및 데이터 전처리

df.info()

1. NaN 값이 많은 deck(객실 데크의 위치), embark_town(승선 도시) 열 삭제

rdf = df.drop(['deck', 'embark_town'], axis=1)
rdf.info()

2. age 열(columns)에 나이가 없는 (NaN) 모든 행(row)을 삭제 → 891 → 714건으로 전처리(177건 삭제)

rdf = rdf.dropna(subset=['age'], how='any', axis=0)
rdf.info()

rdf.head()

학습에 필요한 컬럼(feature) 추출

 

생존여부(survived), 객실등급(pclass), 성별(sex), 나이(age), 같이 탑승한 형제/자매수(sibsp), 같이 탑승한 부모/자녀수(parch)

rdf = rdf[['survived', 'pclass', 'sex', 'age', 'sibsp', 'parch']]
rdf.head()

 

LIST