K-NN
거리 계산 방법
작동 원리 (4단계)
| 파라미터 | 설명 | 영향 |
|---|---|---|
| k (이웃의 수) | 투표에 참여할 이웃의 개수 | k가 작으면 민감(과적합), 크면 일반화(과소적합) |
| 거리 척도 (Metric) | 유사도 계산 방법 | 기본은 유클리드 거리 |
| 가중치 (Weights) | '균등' 또는 '거리 기반' 가중치 적용 | 가까운 점에 더 큰 영향 부여 가능 |
| 탐색 알고리즘 | brute, kd_tree, ball_tree | 속도 및 메모리 효율에 영향 |
| 장점 | 단점 |
|---|---|
| 구현이 간단하고 직관적 | 대규모 데이터에서 느림 (모든 거리 계산 필요) |
| 학습 과정이 없음 (Lazy Learner) | 특성 스케일링에 민감 |
| 다중 클래스 문제도 자연스럽게 해결 | 명시적 모델이 없어 해석 어려움 |
| 데이터 분포가 명확할 때 성능 우수 | 고차원 데이터에서는 성능 저하 (차원의 저주) |
| 분야 | 예시 | 목적 |
|---|---|---|
| 의료 | 환자 증상으로 질병 예측 | 분류 |
| 금융 | 대출 신청자 부도 여부 예측 | 분류 |
| 전자상거래 | 유사 상품 추천 | 분류/회귀 |
| 환경 | 센서 데이터를 이용한 오염도 예측 | 회귀 |
| ID | X1 | X2 | Y |
|---|---|---|---|
| 1 | 25 | 25 | A |
| 2 | 33 | 30 | A |
| 3 | 38 | 30 | B |
| 4 | 45 | 35 | B |
| 5 | 28 | 40 | A |
| ID | X1 | X2 | Y |
|---|---|---|---|
| 6 | 30 | 35 | ? |
① k의 수 결정
② 피처 스케일링
| ID | 원 데이터 | 표준화된 데이터 | ||
|---|---|---|---|---|
| X1 | X2 | Z1 | Z2 | |
| 1 | 25 | 25 | -1.2327 | -1.3728 |
| 2 | 33 | 30 | -0.1121 | -0.3922 |
| 3 | 38 | 30 | 0.5883 | -0.3922 |
| 4 | 45 | 35 | 1.5689 | 0.5883 |
| 5 | 28 | 40 | -0.8125 | 1.5689 |
| 평균 | 33.8 | 32 | ||
| 표준편차 | 7.1 | 5.1 | ||
| ID | 원 데이터 | 표준화된 데이터 | ||
|---|---|---|---|---|
| X1 | X2 | Z1 | Z2 | |
| 6 | 30 | 35 | -0.5323 | 0.5883 |
③ 유사도 측정

④ 최근접 이웃 선택

⑤ 예측

위 예제의 Python 전체 코드
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler
import numpy as np
import matplotlib.pyplot as plt
# 기존 개체
X_train = np.array([[25, 25], [33, 30], [38, 30], [45, 35], [28, 40]])
y_train = np.array([0, 0, 1, 1, 0])
# 새로운 개체
X_test = np.array([[30, 35]])
# 산포도 출력
plt.scatter(X_train[:, 0], X_train[:, 1], c = y_train)
plt.scatter(X_test[:, 0], X_test[:, 1], c = 'red', marker = 'D', s = 100)
plt.xlabel('x1')
plt.ylabel('x2')
plt.show()
# 피처 스케일링
scalerX = StandardScaler()
scalerX.fit(X_train)
X_train_std = scalerX.transform(X_train)
print(X_train_std)
X_test_std = scalerX.transform(X_test)
print(X_test_std)
# 모형화(디폴트 : 유클리드)
knn = KNeighborsClassifier(n_neighbors = 3, metric = 'euclidean')
# 학습
knn.fit(X_train_std, y_train)
# 예측
pred = knn.predict(X_test_std)
print(pred)
# 클래스별 확률 값을 반환
knn.predict_proba(X_test_std)
# 인접한 K개의 개체들에 대한 거리와 색인 반환
dist, index = knn.kneighbors(X_test_std)
print(dist)
print(index)
K-NN의 꽃잎 분류에의 적용 예

from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
from sklearn.neighbors import KNeighborsClassifier
from sklearn import metrics
# 데이터 로드
iris = load_iris()
# 데이터(150개)
X = iris.data
# 꽃의 종류 (0 = setosa, 1=versicolor, 2=virginica)
y = iris.target
# 80 : 20으로 분할
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=4)
# K값을 7로 두고 시행
knn = KNeighborsClassifier(n_neighbors=7)
knn.fit(X_train, y_train)
# 20%의 종류 예측
y_pred = knn.predict(X_test)
# 정확도 반환
scores = metrics.accuracy_score(y_test, y_pred)
print(scores)
결과 : 0.9666666666666667 (96.7%)
classes = {0:'setosa',1:'versicolor',2:'virginica'}
# 새로운 데이터 제시
x_new = [[3,4,5,2], [5,4,2,2]]
y_predict = knn.predict(x_new)
print(classes[y_predict[0]])
print(classes[y_predict[1]])
결과 :
versicolor
setosa
K-NN의 MNIST 손글씨 데이터 적용 예
from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
# 데이터 로드
mnist = fetch_openml('mnist_784', version = 1)
X, y = mnist.data / 255.0, mnist.target.astype(int)
# 데이터 분할
X_train, X_test, y_train, y_test = train_test_split(X, y,;
test_size = 0.1, random_state = 42)
# K-NN 모델 학습
knn = KNeighborsClassifier(n_neighbors = 3)
knn.fit(X_train, y_train)
# 예측 및 정확도 평가
y_pred = knn.predict(X_test)
print(accuracy_score(y_test, y_pred))