034 KNN 분류 상세
키워드: KNN, knn
개요
KNN(K-Nearest Neighbors)은 새로운 데이터를 가장 가까운 K개의 이웃 데이터를 기반으로 분류하는 알고리즘입니다. 단순하지만 효과적인 방법입니다.
실습 환경
- Python 버전: 3.11 권장
- 필요 패키지:
pycaret[full]>=3.0
KNN 원리
- 새로운 데이터 포인트가 들어옴
- 학습 데이터에서 가장 가까운 K개 이웃 찾기
- 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