본문 바로가기
AI/머신러닝

[머신러닝] K-최근접 이웃(K-NN) 분류 알고리즘 - 실습

by snow_white 2022. 4. 11.

1. K-NN 알고리즘이란?

K-최근접 이웃(K-Nearest Neighbor) 알고리즘은 머신러닝에서 사용되는 분류(Classification) 알고리즘입니다.

  • 유사한 특성을 가진 데이터는 유사한 범주에 속하는 경향이 있다는 가정하에 사용합다.
  • 비매개변수 머신러닝 모델입니다.
  • 훈련 단계에서 학습을 하지 않기 때문에 '게으른 학습'이라 부릅니다.
  • 테스트/검증 단계에서 테스트 관측값과 가장 접근한 훈련 관측값을 비교합다.
  • 거리에만 의존하므로 차원의 저주에 따라 예측에 필요한 특징의 개수가 늘어나면 성능이 크게 저하됩니다.

 

Matplotlib

파이썬에서 데이타를 차트나 플롯(Plot)으로 그려주는 라이브러리 패키지로서 가장 많이 사용되는 데이타 시각화(Data Visualization) 패키지입니다.

Keyword: matplotlib.pyplot, plt.plot(), plt.show(), plt.axis(), 포맷 문자열

 

Pyplot

matplotlib.pyplot 모듈은 MATLAB과 비슷하게 명령어 스타일로 동작하는 함수의 모읍니다.

matplotlib.pyplot 모듈의 각각의 함수를 사용해서 간편하게 그래프를 만들고 변화를 줄 수 있습니다.

예를 들어, 그래프 영역을 만들고, 몇 개의 선을 표현하고, 레이블로 꾸미는 등의 일을 할 수 있습니다.

 

Matplotlib를 활용한 간단한 예제

import matplotlib.pyplot as plt

plt.plot([1, 2, 3, 4])
plt.show()
 
import matplotlib.pyplot as plt
import numpy as np

# 200ms 간격으로 균일하게 샘플된 시간
t = np.arange(0., 5., 0.2)

# 빨간 대쉬, 파란 사각형, 녹색 삼각형
plt.plot(t, t, 'r--', t, t**2, 'bs', t, t**3, 'g^')
plt.show()
 
 
 
 
실습해보기
 
matplotlib으로 산점도(scatter plot)을 그려 생선 도미와 빙어를 구분해봅시다.

도미 데이터가 파란색, 빙어 데이터가 주황색으로 표시됩니다.

import matplotlib.pyplot as plt

bream_length = [10,20,30]
bream_weight = [100,200,300]

smelt_length = [1,2,3]
smelt_weight = [10,20,30]

plt.scatter(bream_length, bream_weight)
plt.scatter(smelt_length, smelt_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

 

K-NN 알고리즘을 사용하여 2개의 종류를 분류하는 머신러닝 모델을 직접 훈련해봅시다.

 
fit( ) 메소드는 테스트 데이터에 대해 predict 메서드를 호출해서 예측을 합니다.
 
테스트 세트의 각 데이터 포인트에 대해 훈련 세트에서 가장 가까운 이웃을 계산한 다음 가장 많은 클래스를 찾습니다.
 
score( ) 메소드는 각 테스트 데이터의 예측 결과 정확도를 출력합니다.

 

fish_data는 훈련데이터, fish_target은 정답데이터로써 훈련데이터를 분류했을 때 얼마나 정답률이 높은지 구합니다.

파이썬 머신러닝 라이브러리 싸이킷런을 불러와서 KNeighborsClassifier 모델을 생성합니다.

from sklearn.neighbors import KNeighborsClassifier
import tensorflow
	# 빙어		# 도미
length = [1,2,3,          10,20,30]
weight = [100,200,300,   100,200,300]
fish_data = [[l,w] for l, w in zip(length, weight)] # zip()으로 2차원 리스트로 만듦
print(fish_data)

fish_target = [1]*3 + [0]*3 # 1은 빙어, 0은 도미
print(fish_target)

kn = KNeighborsClassifier()
kn.fit(fish_data, fish_target)
kn.score(fish_data, fish_target)

'''
[[1, 100], [2, 200], [3, 300], [10, 100], [20, 200], [30, 300]]
[1, 1, 1, 0, 0, 0]
0.8333333333333334
'''

정확도가 1이 안 나온다.. 1이 나와야 100% 맞췄다는 의미입니다.

데이터 수가 적어서 그런지..? 데이터 수를 늘려봅시다.

from sklearn.neighbors import KNeighborsClassifier

length = [1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,10,20,30,10,20,30,10,20,30,10,20,30,10,20,30]
weight = [10,20,30,10,20,30,10,20,30,10,20,30,10,20,30,100,200,300,100,200,300,100,200,300,100,200,300,100,200,300]
fish_data = [[l,w] for l, w in zip(length, weight)]
print(fish_data)

fish_target = [1]*15 + [0]*15
print(fish_target)

kn = KNeighborsClassifier()
kn.fit(fish_data, fish_target)
kn.score(fish_data, fish_target) # 1

'''
[[1, 10], [2, 20], [3, 30], [1, 10], [2, 20], [3, 30], [1, 10], [2, 20], [3, 30], [1, 10], [2, 20], [3, 30], [1, 10], [2, 20], [3, 30], [10, 100], [20, 200], [30, 300], [10, 100], [20, 200], [30, 300], [10, 100], [20, 200], [30, 300], [10, 100], [20, 200], [30, 300], [10, 100], [20, 200], [30, 300]]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1.0
'''

데이터 수를 도미, 빙어 각각 3개씩에서 15씩으로 늘리니 정확도(accuracy)가 1로 정확하게 도미와 빙어를 분류할 수 있게 되었습니다. (학부 과정에서 얼핏 듣기론 학습 데이터가 많을 수록 정확한 예측을 하기에 유리하다고 들었습니다. 이를 상기시켜 늘려본 것인데 혹시 제 생각이 다르다면 코멘트 감사히 받겠습니다.)

 

 

KNeighborsClassifier 생성자에 n_neighbors 매개변수를 이용하여 분류 시 고려할 샘플 수를 지정해봅시다.

KNeighborsClassifier 생성자 파라미터는 다음의 의미를 가집니다.

  •   n_neighobrs(default=5): 분류 시 가장 가까운 이웃을 몇 개 고를지에 대한 고려할 인접 샘플 수
  •   weights(default='uniform'): 'distance'로 설정하면, 분류할 때 인접한 샘플의 거리에 따라 다른 가중치 부여 (가까울수록 큰 가중치)
  •   metric(default='minkowski'): 거리계산의 척도 (minkowski, euclidean, mahalanobis 등)
 
오늘 실습은 n_neighobrs 파라미터를 사용합니다.
 
KNeighborsClassifier(n_neighbors=30) 처럼 지정하는 것은 무엇을 의미할까요?
 

빙어 2마리와 도미 28마리,  전체 샘플이 30마리인 데이터를 모두 사용하여 분류 대상을 고려한다는 것입니다. 

즉, 예측을 해보면 30마리 중 28마리가 도미이기 때문에 어떤 데이터를 예측하게 되어도 모두 도미라는 결과를 내기 때문에 정답 데이터 중 28개의 데이터는 맞고, 2개의 데이터는 사실 빙어의 데이터이기 때문에 정확도가 0.933333..이 나오게 됩니다.

실제로 28/30 결과값도 0.93333..로 도미만 다 맞춘 정확도인 것을 확인할 수 있습니다.

from sklearn.neighbors import KNeighborsClassifier
import tensorflow

length = [1,2,3,1,2,3,10,20,30,10,20,30,10,20,30,10,20,30,10,20,30,10,20,30,10,20,30,10,20,30]
weight = [10,20,30,10,20,30,100,200,300,100,200,300,100,200,300,100,200,300,100,200,300,100,200,300,100,200,300,100,200,300]
fish_data = [[l,w] for l, w in zip(length, weight)]

fish_target = [1]*2 + [0]*28

kn30 = KNeighborsClassifier(n_neighbors=30)
kn30.fit(fish_data, fish_target)
kn30.score(fish_data, fish_target)

'''
[[1, 10], [2, 20], [3, 30], [1, 10], [2, 20], [3, 30], [10, 100], [20, 200], [30, 300], [10, 100], [20, 200], [30, 300], [10, 100], [20, 200], [30, 300], [10, 100], [20, 200], [30, 300], [10, 100], [20, 200], [30, 300], [10, 100], [20, 200], [30, 300], [10, 100], [20, 200], [30, 300], [10, 100], [20, 200], [30, 300]]
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0.9333333333333333
'''

# 28/30 = 0.93333..

 

댓글