본문으로 건너뛰기

034 KNN 분류 상세

키워드: KNN, knn

개요

KNN(K-Nearest Neighbors)은 새로운 데이터를 가장 가까운 K개의 이웃 데이터를 기반으로 분류하는 알고리즘입니다. 단순하지만 효과적인 방법입니다.

실습 환경

  • Python 버전: 3.11 권장
  • 필요 패키지: pycaret[full]>=3.0

KNN 원리

  1. 새로운 데이터 포인트가 들어옴
  2. 학습 데이터에서 가장 가까운 K개 이웃 찾기
  3. K개 이웃의 클래스를 다수결로 예측
K=3 예시:
● 새 데이터
○ 클래스 A
■ 클래스 B

가장 가까운 3개: ○○■
다수결: 클래스 A (2:1)

PyCaret에서 KNN

from pycaret.classification import *
from pycaret.datasets import get_data

# 034 데이터 로드
data = get_data('diabetes')
clf = setup(data, target='Class variable', session_id=42, verbose=False)

# 034 KNN 모델 생성
knn = create_model('knn')

주요 하이퍼파라미터

n_neighbors (K)

# 034 n_neighbors: 이웃 수
knn_3 = create_model('knn', n_neighbors=3)
knn_5 = create_model('knn', n_neighbors=5) # 기본값
knn_10 = create_model('knn', n_neighbors=10)
knn_20 = create_model('knn', n_neighbors=20)

weights (가중치)

# 034 weights: 이웃의 가중치
knn_uniform = create_model('knn', weights='uniform') # 동일 가중치 (기본)
knn_distance = create_model('knn', weights='distance') # 거리 역수로 가중치

metric (거리 측정)

# 034 metric: 거리 계산 방법
knn_euclidean = create_model('knn', metric='euclidean') # 유클리드 (기본)
knn_manhattan = create_model('knn', metric='manhattan') # 맨해튼
knn_minkowski = create_model('knn', metric='minkowski') # 민코프스키

algorithm (탐색 알고리즘)

# 034 algorithm: 이웃 탐색 방법
knn_auto = create_model('knn', algorithm='auto') # 자동 선택 (기본)
knn_ball = create_model('knn', algorithm='ball_tree')
knn_kd = create_model('knn', algorithm='kd_tree')
knn_brute = create_model('knn', algorithm='brute') # 전체 탐색

K 값 선택

from pycaret.classification import *
from pycaret.datasets import get_data
import pandas as pd
import matplotlib.pyplot as plt

data = get_data('diabetes')
clf = setup(data, target='Class variable', normalize=True, session_id=42, verbose=False)

results = []

for k in range(1, 31, 2): # 홀수만 (동점 방지)
knn = create_model('knn', n_neighbors=k, verbose=False)
metrics = pull()

results.append({
'k': k,
'accuracy': metrics['Accuracy'].mean(),
'std': metrics['Accuracy'].std()
})

df = pd.DataFrame(results)

# 034 시각화
plt.figure(figsize=(10, 6))
plt.errorbar(df['k'], df['accuracy'], yerr=df['std'], marker='o', capsize=5)
plt.xlabel('K (Number of Neighbors)')
plt.ylabel('Accuracy')
plt.title('KNN: Accuracy vs K')
plt.grid(True)
plt.savefig('knn_k_selection.png', dpi=150)

print(df)
# 034 최적 K 찾기
best_k = df.loc[df['accuracy'].idxmax(), 'k']
print(f"\n최적 K: {best_k}")

스케일링의 중요성

KNN은 거리 기반이므로 스케일링 필수:

from pycaret.classification import *
from pycaret.datasets import get_data

data = get_data('diabetes')

# 034 스케일링 없이
clf1 = setup(data, target='Class variable', normalize=False, session_id=42, verbose=False)
knn1 = create_model('knn', verbose=False)
results1 = pull()

# 034 스케일링 적용
clf2 = setup(data, target='Class variable', normalize=True, session_id=42, verbose=False)
knn2 = create_model('knn', verbose=False)
results2 = pull()

print(f"스케일링 없이: {results1['Accuracy'].mean():.4f}")
print(f"스케일링 적용: {results2['Accuracy'].mean():.4f}")

# 034 스케일링 효과가 매우 큼!

가중치 비교

from pycaret.classification import *
from pycaret.datasets import get_data

data = get_data('iris')
clf = setup(data, target='species', normalize=True, session_id=42, verbose=False)

# 034 uniform vs distance
print("=== Uniform Weights ===")
knn_uniform = create_model('knn', weights='uniform')

print("\n=== Distance Weights ===")
knn_distance = create_model('knn', weights='distance')

튜닝

from pycaret.classification import *
from pycaret.datasets import get_data

data = get_data('diabetes')
clf = setup(data, target='Class variable', normalize=True, session_id=42, verbose=False)

# 034 기본 모델
knn = create_model('knn', verbose=False)

# 034 자동 튜닝
tuned_knn = tune_model(knn, optimize='AUC')

# 034 커스텀 그리드
custom_grid = {
'n_neighbors': [3, 5, 7, 9, 11, 15, 21],
'weights': ['uniform', 'distance'],
'metric': ['euclidean', 'manhattan', 'minkowski']
}

tuned_knn = tune_model(knn, custom_grid=custom_grid, optimize='AUC')

결정 경계 시각화

from pycaret.classification import *
from pycaret.datasets import get_data

data = get_data('iris')
clf = setup(data, target='species', normalize=True, session_id=42, verbose=False)

knn = create_model('knn', n_neighbors=5, verbose=False)

# 034 결정 경계 시각화
plot_model(knn, plot='boundary')

차원의 저주

고차원에서 KNN의 성능이 저하되는 현상:

from pycaret.classification import *
from pycaret.datasets import get_data

data = get_data('diabetes')

# 034 고차원 데이터에서는 PCA 적용 고려
clf = setup(
data,
target='Class variable',
normalize=True,
pca=True,
pca_components=5, # 차원 축소
session_id=42,
verbose=False
)

knn = create_model('knn', verbose=False)

장단점

장점:

  • 단순하고 이해하기 쉬움
  • 학습 단계 없음 (Lazy Learning)
  • 비선형 결정 경계 가능
  • 다중 클래스 자연 지원

단점:

  • 예측이 느림 (모든 데이터와 거리 계산)
  • 대용량 데이터에 부적합
  • 차원의 저주 (고차원에서 성능 저하)
  • 스케일링 필수
  • 최적 K 선택 필요

언제 사용하나?

# 1. 소규모 데이터
# 034 학습 데이터가 작을 때 효과적

# 2. 비선형 결정 경계 필요
# 034 복잡한 패턴을 포착

# 3. 빠른 프로토타이핑
# 034 개념적으로 단순하고 빠르게 테스트

# 4. 추천 시스템
# 034 유사 아이템/사용자 찾기의 기본

# 034 주의: 대용량, 고차원 데이터에서는 비효율적

KNN vs 다른 알고리즘

항목KNN결정 트리로지스틱
학습 시간없음빠름빠름
예측 시간느림빠름빠름
스케일링필수불필요권장
해석력낮음높음중간
대용량부적합적합적합

정리

  • KNN은 K개 최근접 이웃 기반 분류
  • K 값이 작으면 과적합, 크면 과소적합
  • 스케일링 필수 (거리 기반)
  • 소규모 데이터에 적합
  • 예측이 느려서 대용량에 부적합
  • 차원의 저주 주의

다음 글 예고

다음 글에서는 Naive Bayes 분류 상세를 다룹니다.


PyCaret 머신러닝 마스터 시리즈 #034