Python/Sklearn

[Sklearn] 파이썬 k-NN 알고리즘(k-최근접 이웃) 예제

jimmy_AI 2021. 11. 29. 13:50
반응형

지도 학습 알고리즘 중 하나인 k-NN 알고리즘의 파이썬 구현 예제에 대해서 살펴보겠습니다.

k-최근접 이웃 알고리즘은 새로운 데이터에 대해서 가장 가까운 기존의 k개 데이터를 살펴

k개 데이터 중 가장 많은 비율을 차지하는 class로 분류하는 분류 알고리즘인데요.

 

예를 들어, 테스트 데이터에 새로운 사진 A가 들어왔다고 가정해봅시다.

k = 9로 정했을 때, 새로운 사진 A에서 9개의 가장 가까운 사진 중 6개가 고양이, 3개가 강아지 라벨이었다면,

A는 고양이 사진으로 분류하는 예제라고 볼 수 있겠지요.

 

파이썬 사이킷런 k-NN 알고리즘 전처리

k-NN 알고리즘을 구현하기 위해서 필요한 간단한 전처리 과정을 먼저 수행하도록 하겠습니다.

먼저, 데이터셋을 불러오고 학습 데이터 셋 및 테스트 데이터 셋을 분리하도록 하겠습니다.

여기서는 사이킷런에서 기본으로 제공하는 데이터 셋 중 하나인 iris 데이터셋을 사용해보겠습니다.

데이터셋은 sepal과 petal의 길이와 너비에 대한 4가지 feature와 붓꽃 종류를 나타내는 target column으로 구성되어 있습니다. 참고로, 여기서 target은 0, 1, 2 총 3가지 종류의 붓꽃을 의미합니다.

 

feature가 4가지 이기 때문에, 4차원의 feature space에 대해서 가장 가까운 train data point를 찾게 되겠죠. 그런데 말입니다. x축은 도시 인구이고 y축은 평균 기온으로 도시들을 feature space에 나타냈을 때, 도시 인구 1명 차이와 평균 기온 1도 차이를 같은 1 차이라고 볼 수 있을까요?

 

이러한 scale의 문제를 해결하기 위하여 정규화 과정이 k-NN 알고리즘 수행 전에 반드시 수반되어야 합니다.

여기서는 각 column의 최소값을 0, 최대값을 1로 기준 잡고 상대적인 값으로 정규화를 진행하는 MinMaxSclaer를 통하여 정규화를 진행해보겠습니다.

from sklearn.preprocessing import MinMaxScaler

# 정규화 작업
scaler = MinMaxScaler()
scaler.fit(X_train)
X_train = scaler.transform(X_train)

pd.DataFrame(X_train, columns = df.columns[:-1]).head()

이제 각 column 들의 scale이 0~1 사이로 동등하게 맞춰진 것을 확인할 수 있지요?

이 정규화된 feature들의 값으로 상대적인 거리를 재도록 하겠습니다.

반응형

파이썬 사이킷런 k-최근접 이웃 알고리즘 적용, 성능 평가, k 정하기

그렇다면 k개의 가장 가까운 학습 데이터셋을 살펴본다 했는데, k라는 숫자는 어떻게 정해야 할까요?

여기서는 보통 k = 3정도 부터 시작해서 k를 늘려가며 모델의 테스트 정확도가 어떤 k에서 가장 높은지를 살펴 보는 것이 가장 좋습니다.

 

먼저, test 데이터셋에도 같은 정규화를 실행해준 다음에 모델을 선언해볼까요?

from sklearn.neighbors import KNeighborsClassifier

# test 데이터에도 같은 정규화 적용
X_test = scaler.transform(X_test)

# kNN 모델 선언
k = 3
model = KNeighborsClassifier(n_neighbors = k)
# 모델 학습
model.fit(X_train, y_train)

이제 모델의 정확도를 통하여 성능 평가를 진행해보겠습니다.

약 96.7%라는 높은 정확도가 출력되었네요.

 

이제 k를 여러 가지로 설정하면서 정확도 추이 그래프를 그려보고 가장 최적의 k를 찾아보도록 하겠습니다.

import matplotlib.pyplot as plt

k_range = range(3,40)

# k에따른 accuracy 저장
accuracy_list = []

# 각 k마다 모델 테스트
for k in k_range:
    model = KNeighborsClassifier(n_neighbors = k)
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    accuracy_list.append(accuracy_score(y_test, y_pred))
    
# 시각화
plt.plot(k_range, accuracy_list, 'o--', color = 'orange')
plt.xlabel("k")
plt.ylabel("test accuracy")
plt.show()

k = 3 ~ 40까지 테스트해보았을 때, k = 23일 때, 정확도 100%가 등장하긴 했으며, k가 너무 커지면 다른 클래스의 데이터도 많이 포함되기에 정확도가 다소 떨어지는 것을 확인할 수 있었습니다.

 

여기서는 데이터셋이 간단하여 k에 대한 테스트 결과가 다소 단순하게 나왔지만, k가 작은 경우는 과적합의 문제가 있고 k가 크면 다른 클래스의 데이터가 많이 섞이는 trade-off가 있기에 데이터셋에 따라 여러 k에 대해 실험을 해보시면 다양한 결과가 나올 수 있을 것입니다.