Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

Matplotlib으로 k-NN 결정 경계 그래프 그리는 방법

k-최근접 이웃(k-Nearest Neighbors, k-NN)은 가장 널리 쓰이는 머신러닝 분류 알고리즘 중 하나로, 새로운 데이터를 주변 k개 이웃의 다수결로 분류합니다. 학습된 모델이 클래스 간 영역을 어떻게 나누는지 보여주는 결정 경계(decision boundary)를 시각화하면 모델의 동작 방식을 직관적으로 파악할 수 있습니다. 이 글에서는 Matplotlib과 scikit-learn을 활용해 k-NN 결정 경계 그래프를 그리는 방법을 단계별로 살펴보겠습니다.

구현 단계

  • 그림(figure) 크기를 설정하고 서브플롯 주변과 사이의 여백을 조정합니다.

  • 이웃의 개수를 지정하는 n_neighbors 변수를 초기화합니다.

  • scikit-learn에서 iris(붓꽃) 분류 데이터셋을 불러옵니다.

  • x, y에 사용할 데이터 포인트를 생성합니다. 여기서는 꽃받침(sepal) 길이와 너비 두 가지 특성만 사용합니다.

  • 결정 영역 배경에 사용할 연한 색상 팔레트와 데이터 포인트에 사용할 진한 색상 팔레트를 각각 준비합니다.

  • k-최근접 이웃 투표 방식을 구현한 KNeighborsClassifier 분류기를 생성하고 학습 데이터에 적합(fit)시킵니다.

  • x축과 y축의 최솟값(x_min, y_min)과 최댓값(x_max, y_max)을 구해 그래프의 표시 범위를 정합니다.

  • 새 figure를 생성하거나 기존 figure를 활성화합니다.

  • contourf 플롯으로 예측 결과를 배경에 채워 결정 영역을 표현합니다.

  • X 데이터셋으로 산점도(scatter plot)를 그립니다.

  • x축·y축 레이블, 그래프 제목, 축 범위를 설정합니다.

  • show() 메서드를 호출해 그림을 화면에 출력합니다.

전체 예제 코드

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.colors import ListedColormap
from sklearn import neighbors, datasets

# 그림 크기와 레이아웃 설정
plt.rcParams['figure.figsize'] = [7.00, 3.50]
plt.rcParams['figure.autolayout'] = True

# 이웃의 개수
n_neighbors = 15

# iris 데이터셋 로드 (처음 2개 특성: 꽃받침 길이, 꽃받침 너비)
iris = datasets.load_iris()
X = iris.data[:, :2]
y = iris.target
h = .02  # 격자 간격

# 연한 색(결정 영역용) / 진한 색(데이터 포인트용) 팔레트
cmap_light = ListedColormap(['orange', 'cyan', 'cornflowerblue'])
cmap_bold = ['darkorange', 'c', 'darkblue']

# k-NN 분류기 생성 및 학습
clf = neighbors.KNeighborsClassifier(n_neighbors, weights='uniform')
clf.fit(X, y)

# 그래프 표시 범위 계산
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                     np.arange(y_min, y_max, h))

# 격자의 모든 좌표에 대해 클래스 예측
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

plt.figure()

# 결정 경계를 배경에 채우기
plt.contourf(xx, yy, Z, cmap=cmap_light)

# 실제 데이터 포인트 산점도
sns.scatterplot(x=X[:, 0], y=X[:, 1], hue=iris.target_names[y],
                palette=cmap_bold, alpha=1.0, edgecolor='black')

plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())

plt.title("3-Class classification (k = %i, weights = 'uniform')" % n_neighbors)

plt.xlabel(iris.feature_names[0])
plt.ylabel(iris.feature_names[1])

plt.show()

코드 핵심 포인트

  • np.meshgrid: 결정 경계를 그리려면 그래프 영역 전체를 h=0.02 간격의 촘촘한 격자로 나눈 뒤, 모든 격자점에 대해 클래스를 예측해야 합니다. meshgrid는 이러한 2차원 격자 좌표를 손쉽게 만들어 줍니다.

  • plt.contourf: 격자점별 예측 결과(Z)를 등고선 형태로 배경에 채워, 클래스별 결정 영역을 색으로 구분해 보여줍니다.

  • sns.scatterplot: hue 옵션에 클래스 이름을 지정하면 클래스마다 다른 색으로 실제 데이터 포인트를 표시할 수 있어, 배경의 결정 영역과 함께 비교하기 좋습니다.

  • weights='uniform': 모든 이웃에 동일한 가중치를 부여하는 방식입니다. 'distance'로 바꾸면 가까운 이웃일수록 더 큰 영향력을 가지며, 결정 경계의 모양도 달라집니다.

  • n_neighbors 값 조절: k 값을 작게 하면 경계가 데이터에 민감하게 구부러져 과적합(overfitting) 위험이 커지고, 크게 하면 경계는 매끄러워지지만 과소적합(underfitting)될 수 있습니다.

실행 결과

위 코드를 실행하면 아래와 같이 3개 클래스의 결정 경계가 색으로 구분된 그래프가 출력됩니다.

Matplotlib으로 k-NN 결정 경계 그래프 그리는 방법