Notice
Recent Posts
Recent Comments
Link
«   2024/10   »
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
Archives
Today
Total
관리 메뉴

에코프로.AI

[머신러닝] KNN(K-최근접 이웃) 알고리즘 구현 본문

AI Tutorial

[머신러닝] KNN(K-최근접 이웃) 알고리즘 구현

AI_HitchHiker 2024. 8. 13. 19:56

KNN(K-최근접 이웃) 소개

  • KNN(K-최근접 이웃)은 거리 기반 모델입니다. 즉 각 데이터 간의 거리를 활용해서 새로운 데이터를 예측하는 모델입니다.
    • 이때 가까이에 있는 데이터를 고려하여 예측값이 결정됩니다.
    • K Nearest Neighbors 라는 이름은 이를 잘 반영하고 있는데, K개의 가장 가까운 이웃 데이터에 의해 예측된다는 의미입니다.
  • 다중 분류 문제에서 가장 간편히 적용할 수 있는 알고리즘입니다. 물론 최신 알고리즘들도 다중 분류 문제에 사용하나, 데이터가 크지 않고 예측이 까다롭지 않은 상황에서 KNN을 사용하면 신속하고 쉽게 예측 모델을 구현할 수 있습니다.
  • 이러 한 특성으로 베이스라인 모델로도 사용합니다.
  • 장점
    • 수식에 대한 설명이 필요 없을 만큼 직관적이고 간단합니다.
    • 선형모델과 다르게 별도의 가정이 없습니다. (예를 들어 선형회귀는 독립변수와 종속변수의 선형관계를 가정하고 있기 때문에, 이 가정이 들어 맞지 않는 데이터게 취약하나, KNN은 이러한 가정이 없어서 더 자유롭습니다.
  • 단점
    • 데이터가 커질수록 상당히 느려질 수 있습니다.
    • 아웃라이어(이상치)에 취약합니다.
  • 유용한곳
    • 주로 분류에서 사용되며, 로지스틱회귀로 해결할 수 없는 3개 이상의 목표 변수들도 분류할 수 있습니다.
    • 작은 데이터셋에 적합합니다.

일반적인 KNN 모델링 방법

  • 아래와 같이 sklearn.neighbors 의 KNeighborsClassifier 모델을 사용하여 모델링
    from sklearn.neighbors import KNeighborsClassifier
    from sklearn.metrics import accuracy_score
    
    def knn(x_train, y_train, x_test, k=2):
        pred = []
    
        knn = KNeighborsClassifier(n_neighbors=2) # 모델 생성 (기본값 : n_neighbors=5)
        knn.fit(x_train, y_train) # 학습
    
        pred = knn.predict(x_train) # 예측 (학습 데이터)
        print(accuracy_score(y_train, pred))
    
        pred = knn.predict(x_test) # 예측 (테스트 데이터)
    
    	return pred

 

KNN 알고리즘 직접 구현

테스트 데이터 생성

np.random.seed(0)

x_train = np.random.randn(10, 2)
y_train = np.array([0, 1] * 5)

x_test = np.random.randn(5, 2)

print(x_train.shape, y_train.shape, x_test.shape)
print('x_train : ', x_train)
print('y_train : ', y_train)
print('x_test : ', x_test)

데이터 분포 확인하기

plt.plot(x_train[:,0], x_train[:,1], 'ro')

KNN 알고리즘 구현하기 (거리계산은 유클리드 거리로 계산)

 

import numpy as np

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

# x_train : 2차원 데이터 배열로 각 행은 데이터 포인트를 나타내며,
# - 첫 번째 열은 x1값
# - 두 번째 열은 x2값
# y_train : 데이터 포인트의 클래스를 나타내는 레이블
def my_knn(x_train, y_train, x_test, k=2):
  pred = []

  for _x_test in x_test:
    # 1. 거리계산 (모든 데이터에 대한)
    # - test 데이터와 train 모든 데이터와의 유클리드 거리를 구합니다.
    distances = np.sqrt(np.sum((x_train-_x_test)**2, axis = 1))

    # 2. k개의 가장 가까운 점을 찾기
    # - 위에서 구한 distances에서 작은순으로 정렬후, 설정된 k개의 y_train값을 구합니다.
    # argsort 함수를 사용하여, distances 배열에서 가장 작은 k개의 값을 가지는 인덱스를 찾고
    # 이를 y에 인덱싱하여 k개의 이웃 데이터 포인트의 클래스를 얻습니다.
    nearest_neighbors = y_train[np.argsort(distances)[:k]]

    # 3. 2번에서 찾은 점의 클래스(라벨)을 확인
    # - 클래스(라벨)을 확인하여, 가장 많은 라벨을 반환, 동일한 경우에는 순번이 앞에 있는 라벨 반환
    # bincount : 0부터 가장 큰 클래스 값까지의 등장 횟수를 계산하여 배열로 반환합니다.
    # np.argmax : 가장 큰 값을 가지는 클래스를 예측
    pred.append(np.argmax(np.bincount(nearest_neighbors)))

  return pred

예측하기

예측값 확인

pred = my_knn(x_train, y_train, x_test)
pred

산점도 그리기

- 파란색으로 표시된것이 train데이터이고, 빨간색으로 표시된것이 test데이터로 예측된 값입니다.

import seaborn as sns

sns.scatterplot(x = x_train[:, 0], y = x_train[:, 1], style=y_train, color='blue', s=100)
sns.scatterplot(x = x_test[:, 0], y = x_test[:, 1], style=pred, color='red', s=100)