Scikit-learn KNN 분류

scikit-learnBeginner
지금 연습하기

소개

scikit-learn 을 사용한 K-최근접 이웃 (KNN) 분류 실습에 오신 것을 환영합니다! scikit-learn 은 머신러닝을 위한 강력하고 인기 있는 Python 라이브러리입니다. KNN 알고리즘은 가장 간단하면서도 효과적인 분류 알고리즘 중 하나입니다. 이 알고리즘은 특징 공간에서 'k'개의 가장 가까운 이웃의 다수 클래스를 기반으로 새로운 데이터 포인트를 분류합니다. 본 실습에서는 유명한 Iris 데이터셋을 로드하고, 이를 훈련 세트와 테스트 세트로 분할하고, KNN 분류기를 초기화 및 훈련하고, 마지막으로 훈련된 모델을 사용하여 새롭고 보지 못한 데이터에 대한 예측을 수행하는 등 머신러닝 모델 구축의 전체 과정을 살펴보겠습니다. 본 실습이 끝나면 scikit-learn 에서의 지도 학습 (supervised learning) 에 대한 기본적인 워크플로우를 확실하게 이해하게 될 것입니다.

datasets.load_iris() 로 Iris 데이터셋 로드하기

이 단계에서는 필요한 데이터셋을 로드하는 것부터 시작합니다. scikit-learn 에 편리하게 포함된 고전적인 Iris 데이터셋을 사용할 것입니다. 먼저 sklearn에서 datasets 모듈을 가져와야 합니다. 그런 다음 load_iris() 함수를 호출하여 데이터를 가져옵니다.

load_iris() 이해하기:

  • 반환 타입: 다음을 포함하는 Bunch 객체 (사전과 유사) 를 반환합니다.
    • .data: 특징 행렬 (150 개 샘플 × 4 개 특징: 꽃받침 길이, 꽃받침 너비, 꽃잎 길이, 꽃잎 너비)
    • .target: 레이블 배열 (종: 0=setosa, 1=versicolor, 2=virginica)
    • .feature_names: 4 개 특징의 이름
    • .target_names: 3 개 종의 이름
  • 목적: 분류 연습을 위해 깨끗하고 바로 사용할 수 있는 데이터셋을 제공합니다.

이것들을 각각 변수 Xy에 할당할 것입니다. 이는 머신러닝에서 일반적인 관례입니다 (X 는 특징, y 는 레이블).

왼쪽 편집기에서 main.py 파일을 열고 다음 코드를 추가하세요.

from sklearn import datasets

## Load the iris dataset
iris = datasets.load_iris()

## Assign features to X and labels to y
X = iris.data
y = iris.target

## You can print the shape to see the dimensions
print("Features shape:", X.shape)
print("Labels shape:", y.shape)

이제 터미널에서 스크립트를 실행하여 출력을 확인하세요.

python3 main.py

특징 행렬과 레이블 벡터의 차원을 볼 수 있습니다.

Features shape: (150, 4)
Labels shape: (150,)

이는 각 샘플에 대해 150 개의 샘플 (꽃) 과 4 개의 특징이 있음을 의미합니다.

sklearn.model_selection 의 train_test_split 을 사용하여 데이터를 훈련 및 테스트 세트로 분할

이 단계에서는 데이터셋을 훈련 세트와 테스트 세트의 두 부분으로 분할합니다. 이는 보지 못한 데이터에 대한 모델 성능을 평가하기 위한 머신러닝의 중요한 단계입니다.

train_test_split() 매개변수 이해하기:

  • test_size=0.3: 데이터의 30% 를 테스트용으로, 70% 를 훈련용으로 예약합니다.
  • random_state=42: 재현 가능한 분할을 보장합니다 (실행할 때마다 동일한 난수 시드 사용).
  • 목적: 보지 못한 데이터로 모델을 평가하여 과적합 (overfitting) 을 방지합니다.
  • 출력: 네 개의 배열을 반환합니다: X_train, X_test, y_train, y_test.

훈련 세트로 모델을 훈련시킨 다음, 테스트 세트로 예측 능력을 테스트합니다. scikit-learn 은 이 목적을 위해 train_test_split이라는 유용한 함수를 제공합니다. sklearn.model_selection에서 이 함수를 가져와야 합니다.

main.py 파일 끝에 다음 코드를 추가하세요.

from sklearn.model_selection import train_test_split

## Split data into training and testing sets
## test_size=0.3 means 30% of the data will be used for testing
## random_state ensures reproducibility
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

## Print the shapes of the new sets
print("X_train shape:", X_train.shape)
print("X_test shape:", X_test.shape)

이제 스크립트를 다시 실행하세요.

python3 main.py

출력에는 훈련 및 테스트 세트의 차원이 포함됩니다.

Features shape: (150, 4)
Labels shape: (150,)
X_train shape: (105, 4)
X_test shape: (45, 4)

sklearn.neighbors 의 KNeighborsClassifier 를 n_neighbors=3 으로 초기화

이 단계에서는 K-최근접 이웃 (K-Nearest Neighbors) 분류기를 초기화합니다. KNN 의 핵심 아이디어는 데이터 포인트의 클래스를 예측하기 위해 가장 가까운 'k'개의 이웃 클래스를 살펴보는 것입니다.

KNeighborsClassifier() 매개변수 이해하기:

  • n_neighbors=3: 예측을 위해 고려할 가장 가까운 이웃의 수
    • 작은 값 (예: 1-3): 노이즈에 더 민감하며 과적합될 수 있습니다.
    • 큰 값 (예: 5-7): 더 부드러운 결정 경계 (decision boundaries) 를 가지며 더 견고합니다.
  • 알고리즘 동작: 예측 시, k 개의 가장 가까운 훈련 포인트를 찾아 다수결 투표 (majority voting) 를 사용합니다.
  • 훈련 단계 없음: KNN 은 "게으른 학습자 (lazy learner)"입니다. 훈련 데이터를 저장하고 예측 중에 계산합니다.

KNeighborsClassifier는 scikit-learn 에서 이 알고리즘을 구현하는 클래스입니다. sklearn.neighbors에서 이 클래스를 가져와야 합니다. 분류기 객체를 생성하고 clf라고 이름을 지정해 보겠습니다.

main.py 파일 끝에 다음 코드를 추가하세요.

from sklearn.neighbors import KNeighborsClassifier

## Initialize the KNN classifier with n_neighbors=3
clf = KNeighborsClassifier(n_neighbors=3)

이 코드는 출력을 생성하지 않지만, 다음 단계에서 훈련할 준비가 된 분류기 객체를 메모리에 생성합니다.

clf.fit(X_train, y_train) 으로 분류기 학습

이 단계에서는 훈련 데이터를 사용하여 분류기를 학습시키거나 'fit'합니다. KNN 알고리즘의 경우, '훈련' 단계는 매우 간단합니다. 전체 훈련 데이터셋 (X_trainy_train) 을 저장하는 것만 포함됩니다.

.fit() 메서드 이해하기:

  • 입력 매개변수: X_train (특성 행렬), y_train (타겟 레이블)
  • 기능: 예측 시 나중에 사용할 수 있도록 훈련 데이터를 메모리에 저장합니다.
  • KNN 특수성: 다른 알고리즘과 달리 KNN 은 fit 중에 매개변수를 학습하지 않습니다.
  • 목적: 새로운 데이터에 대한 예측을 위해 모델을 준비합니다.

새로운 포인트에 대한 예측이 필요할 때, 알고리즘은 이 저장된 데이터셋에서 'k'개의 가장 가까운 포인트를 찾아 결정을 내립니다. scikit-learn 에서 모델을 훈련시키려면 분류기 객체의 .fit() 메서드를 사용합니다. 이 메서드는 훈련 특성 (X_train) 과 해당 훈련 레이블 (y_train) 을 인수로 받습니다.

main.py 끝에 다음 코드 줄을 추가하세요.

## Train the classifier using the training data
clf.fit(X_train, y_train)

print("Classifier trained successfully.")

코드를 추가한 후 스크립트를 실행하세요.

python3 main.py

분류기가 성공적으로 훈련되었다는 확인 메시지가 표시됩니다.

Features shape: (150, 4)
Labels shape: (150,)
X_train shape: (105, 4)
X_test shape: (45, 4)
Classifier trained successfully.

clf.predict(X_test) 로 클래스 예측

이 마지막 단계에서는 훈련된 분류기를 사용하여 테스트 데이터에 대한 예측을 수행합니다. 이제 모델이 훈련 데이터로부터 '학습'했으므로, 이전에 본 적 없는 테스트 세트의 특성 (X_test) 을 모델에 제공하고 각 샘플에 대한 클래스를 예측하도록 요청할 수 있습니다.

.predict() 메서드 이해하기:

  • 입력 매개변수: X_test (보지 못한 데이터의 특성 행렬)
  • 알고리즘 프로세스: 각 테스트 샘플에 대해 훈련 데이터에서 k 개의 가장 가까운 이웃을 찾아 다수결 투표를 사용합니다.
  • 출력: 예측된 클래스 레이블 배열 (입력 샘플과 동일한 길이)
  • 거리 측정 기준: 기본적으로 유클리드 거리 (Euclidean distance) 를 사용하여 포인트 간의 유사성을 측정합니다.
  • 목적: 새롭고 보지 못한 데이터에 대한 모델 성능을 평가합니다.

이는 .predict() 메서드를 사용하여 수행됩니다. 이 메서드는 테스트 특성 (X_test) 을 입력으로 받아 예측된 레이블의 배열을 반환합니다. 이러한 예측을 predictions라는 변수에 저장하고 콘솔에 출력할 것입니다. 실제 레이블 (y_test) 을 출력하여 모델이 얼마나 잘 수행되었는지 확인할 수도 있습니다.

마지막 코드 조각을 main.py 파일에 추가하세요.

## Make predictions on the test data
predictions = clf.predict(X_test)

print("Predictions on test data:", predictions)
print("Actual labels of test data:", y_test)

이제 전체 스크립트를 실행하세요.

python3 main.py

테스트 세트에 대한 예측된 클래스 레이블 배열과 실제 레이블 배열이 차례로 표시됩니다.

... (previous output) ...
Classifier trained successfully.
Predictions on test data: [1 0 2 1 1 0 1 2 1 1 2 0 0 0 0 1 2 1 1 2 0 2 0 2 2 2 2 2 0 0 0 0 1 0 0 2 1
 0 0 0 2 1 1 0 0]
Actual labels of test data: [1 0 2 1 1 0 1 2 1 1 2 0 0 0 0 1 2 1 1 2 0 2 0 2 2 2 2 2 0 0 0 0 1 0 0 2 1
 0 0 0 2 1 1 0 0]

참고: 출력 배열은 여기에 전체 표시됩니다. 두 배열을 비교하면 예측이 실제 레이블과 완벽하게 일치하는 것을 볼 수 있으며, 이는 이 테스트 세트에서 모델 성능이 매우 우수함을 나타냅니다.

KNN 분류 결과 시각화

이 보너스 단계에서는 KNN 분류 결과를 더 잘 이해하기 위한 시각화를 생성합니다. 시각화는 모델이 얼마나 잘 수행되었는지 확인하고 KNN 알고리즘이 생성한 결정 경계 (decision boundaries) 를 이해하는 데 도움이 됩니다.

분류에서의 데이터 시각화 이해하기:

  • 산점도 (Scatter plots): 특성 간의 관계와 클래스가 어떻게 분포하는지 보여줍니다.
  • 색상 코딩 (Color coding): 다른 색상은 다른 클래스 (종) 를 나타냅니다.
  • 훈련 vs 테스트 데이터: 모델의 일반화 (generalization) 를 이해하는 데 도움이 됩니다.
  • 예측 정확도 (Prediction accuracy): 예측된 레이블과 실제 레이블을 시각적으로 비교합니다.

시각화를 생성하기 위해 main.py 파일 끝에 다음 코드를 추가하세요.

import matplotlib.pyplot as plt
import numpy as np

## Create subplots for multiple visualizations
fig, axes = plt.subplots(1, 2, figsize=(15, 6))

## Plot 1: Training data with different colors for each class
scatter1 = axes[0].scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap='viridis', alpha=0.7, s=50)
axes[0].set_xlabel('Sepal Length (cm)')
axes[0].set_ylabel('Sepal Width (cm)')
axes[0].set_title('Training Data Distribution')
axes[0].legend(*scatter1.legend_elements(), title="Classes")

## Plot 2: Test data predictions vs actual labels
## Create a comparison: correct predictions vs incorrect ones
test_predictions = clf.predict(X_test)
correct_predictions = (test_predictions == y_test)

## Plot correct predictions
correct_mask = correct_predictions
scatter2_correct = axes[1].scatter(X_test[correct_mask, 0], X_test[correct_mask, 1],
                                  c=y_test[correct_mask], cmap='viridis', alpha=0.7, s=50, marker='o')

## Plot incorrect predictions with different marker
incorrect_mask = ~correct_predictions
if np.any(incorrect_mask):
    scatter2_incorrect = axes[1].scatter(X_test[incorrect_mask, 0], X_test[incorrect_mask, 1],
                                        c=test_predictions[incorrect_mask], cmap='viridis',
                                        alpha=0.7, s=80, marker='x', edgecolors='red', linewidths=2)

axes[1].set_xlabel('Sepal Length (cm)')
axes[1].set_ylabel('Sepal Width (cm)')
axes[1].set_title('Test Data: Predictions vs Actual\n(correct=●, incorrect=✕)')

## Create legend
legend_elements = [plt.Line2D([0], [0], marker='o', color='w', markerfacecolor='gray', markersize=8, label='Correct'),
                   plt.Line2D([0], [0], marker='x', color='red', markersize=8, label='Incorrect')]
axes[1].legend(handles=legend_elements)

plt.tight_layout()
plt.savefig('knn_classification_results.png', dpi=150, bbox_inches='tight')
print("Visualization saved to knn_classification_results.png")

## Additional: Show prediction accuracy
accuracy = np.mean(correct_predictions) * 100
print(f"Model Accuracy: {accuracy:.1f}%")

업데이트된 스크립트를 실행하세요.

python3 main.py

다음과 같은 출력을 포함하여 보게 될 것입니다.

... (previous output) ...
Visualization saved to knn_classification_results.png
Model Accuracy: 100.0%

KNN Classification Results Visualization

시각화 내용:

  • 왼쪽 플롯: 실제 종별로 색상이 지정된 훈련 데이터 포인트의 분포
  • 오른쪽 플롯: 테스트 데이터 포인트 표시:
    • 원 (●): 올바르게 분류된 포인트
    • 십자 (✕): 잘못 분류된 포인트 (있는 경우)
  • 정확도 점수: 올바른 예측의 전체 백분율

이 시각화는 다음을 이해하는 데 도움이 됩니다.

  1. 특성 공간에서 클래스가 어떻게 분포하는지
  2. 모델이 과적합 (overfitting) 되었는지 또는 일반화를 잘 하고 있는지
  3. 분류에 어려움을 겪을 수 있는 영역
  4. KNN 모델의 효과를 시각적으로 확인

요약

이 랩을 완료하신 것을 축하드립니다! scikit-learn 을 사용하여 K-Nearest Neighbors 분류 모델을 성공적으로 구축하고 훈련했습니다. 지도 학습 (supervised machine learning) 프로젝트의 기본 워크플로우를 배웠으며, 여기에는 다음이 포함됩니다.

  • sklearn.datasets를 사용하여 데이터셋 로드하기.
  • train_test_split으로 데이터를 훈련 세트와 테스트 세트로 분할하기.
  • 분류기 초기화하기, 이 경우 KNeighborsClassifier.
  • .fit() 메서드를 사용하여 훈련 데이터로 모델 훈련하기.
  • .predict() 메서드를 사용하여 새롭고 보지 못한 데이터에 대한 예측하기.
  • 모델 성능 및 결정 패턴을 이해하기 위해 결과 시각화하기.

이 과정은 많은 머신러닝 작업의 기초를 형성합니다. 여기에서 정확도 (accuracy), 정밀도 (precision), 재현율 (recall) 과 같은 지표를 사용하여 모델 성능을 보다 공식적으로 평가하는 방법을 탐색하거나, n_neighbors의 다른 값을 실험하여 결과에 미치는 영향을 확인할 수 있습니다. 또한 결정 경계 (decision boundaries) 를 시각화하거나 KNN 분류기에서 다른 거리 측정 기준 (distance metrics) 을 사용해 볼 수도 있습니다.