머신러닝&딥러닝

머신러닝 & 딥러닝 기초 22편 | KNN 알고리즘 개념부터 Scikit-learn 구현까지

SecLogs YJ 2026. 3. 17. 23:06
목차

1. K-최근접 이웃(KNN) 알고리즘
  1-1 KNN을 사용하는 경우
  1-2 KNN 작동 원리
  1-3 KNN 주요 특징
2. Scikit-learn을 이용한 KNN
3. K 값
  3-1 K 값이 작을 경우
  3-2 K 값이 클 경우
  3-3 K 값 선택 시 고려 사항
4. Scikit-learn을 이용한 K 값 선택
5. 모델 성능 향상 및 하이퍼파라미터 튜닝
  5-1 데이터 전처리
  5-2 거리 계산 방식 선택
  5-3 하이퍼파라미터 튜닝
6. Scikit-learn을 이용한 모델 성능 향상 및 하이퍼파라미터 튜닝

 

1. K-최근접 이웃(KNN) 알고리즘

KNN(K-Nearest Neighbors)은 지도 학습(Supervised Learning) 알고리즘 중 하나이다.

새로운 데이터가 주어졌을 때, 기존 데이터와의 거리(유사도)를 기반으로 결과를 예측한다.

 

즉, 새로운 데이터와 가장 가까운 K개의 이웃 데이터를 찾은 뒤, 이 이웃들의 정보를 이용해 결과를 결정한다.

 

KNN은 분류(Classification)와 회귀(Regression) 문제 모두에 사용할 수 있지만, 실습이나 입문 예제에서는 분류 문제에 더 자주 사용된다.

  • 분류 : 데이터가 어떤 클래스에 속하는지 판단
  • 회귀 : 연속적인 값을 예측

예를 들어

  • 이메일이 스팸인지 정상인지 분류
  • 환자가 특정 질병을 가지고 있는지 예측

등과 같은 문제에 활용될 수 있다.

 

1-1 KNN을 사용하는 경우

KNN은 특히 다음과 같은 상황에서 효과적으로 사용된다.

  • 데이터의 패턴이 비선형적이고 복잡한 경우
  • 데이터 간 유사성이 중요한 문제

하지만, 다음과 같은 경우에는 성능이 저하될 수 있다.

  • 데이터의 개수가 매우 많은 경우
  • 데이터의 차원이 높은 경우

이러한 경우에는 차원 축소 또는 데이터 전처리를 통해 성능을 개선할 수 있다.

 

1-2 KNN 작동 원리

KNN 알고리즘은 다음과 같은 단계로 동작한다.

 

1) 훈련 데이터 준비

먼저 여러 개의 특징(feature)을 가진 데이터를 준비한다.

 

각 데이터는 다음 정보를 가진다.

  • 특징 값(feature)
  • 정답 레이블(label) 또는 실제 값

이 데이터들은 이후 예측 과정에서 기준이 되는 데이터로 사용된다.

 

2) 거리 계산

새로운 데이터가 입력되면, 이 데이터와 기존 훈련 데이터 사이의 거리(distance)를 계산한다.

 

가장 일반적으로 사용되는 거리 계산 방법은 유클리드 거리(Euclidean Distance)이다.

유클리드 거리는 두 점 사이의 가장 짧은 직선 거리를 의미한다.

 

이 과정을 통해 새로운 데이터와 가장 가까운 데이터들을 찾을 수 있다.

 

3) K개의 이웃 선택

거리 계산이 끝나면 가장 가까운 K개의 데이터 포인트를 선택한다.

 

여기서 K는 사용자가 미리 설정하는 값이며 '하이퍼파라미터(Hyperparameter)'라고 한다.

 

K 값의 크기에 따라 모델의 결과와 성능이 달라질 수 있다.

 

4) 결과 결정

선택된 K개의 이웃을 이용하여 최종 예측 결과를 결정한다.

  • 분류의 경우
    • K개의 이웃 중 가장 많이 나타나는 클래스를 선택한다.
    • 이를 다수결(Majority Voting) 방식이라고 한다.
    • 예시
      • 이웃 클래스 = [A, A, B, A, B]
      • 결과 = A
  • 회귀의 경우
    • K개의 이웃이 가진 값들의 평균을 계산하여 결과를 예측한다.
    • 예시
      • 이웃 값 = [120, 130. 140]
      • 예측 값 = 130

 

1-3  KNN 주요 특징

KNN 알고리즘은 다음과 같은 특징을 가진다.

 

1) 학습 과정이 단순하다.

KNN은 일반적인 머신러닝 모델처럼 복잡한 학습 과정을 거치지 않는다.

 

훈련 단계에서는 별도의 복잡한 모델을 만드는 대신 데이터를 저장하고, 새로운 데이터가 들어오면 그때 거리 계산을 수행한다.

이러한 특징 때문에 KNN은 Lazy Learning 알고리즘이라고도 불린다.

 

2) 이해와 구현이 쉽다.

KNN은 데이터 간 거리를 계산하여 결과를 예측하는 방식이기 때에 알고리즘 구조가 비교적 단순다.

 

3) 다양한 문제에 활용이 가능하다.

KNN은 분류와 회귀 문제 모두에 사용할 수 있다.

  • 분류 예) 이메일 스팸 탐지, 질병 진단 등
  • 회귀 예) 주택 가격 예측, 판매량 예측

 

2. Scikit-learn을 이용한 KNN

 

예제 1) 라이브러리 불러오기

KNN 분류를 수행하기 위해 필요한 라이브러리를 불러오는 단계이다.

from sklearn.datasets import load_wine          # Wine 데이터셋 로드
from sklearn.model_selection import train_test_split   # 데이터 분리
from sklearn.neighbors import KNeighborsClassifier     # KNN 알고리즘 사용
from sklearn.metrics import classification_report, accuracy_score  # 성능 평가

 

  • load_wine : Scikit-learn에서 제공하는 예제용 Wine 데이터셋
  • train_test_split: 데이터를 학습용과 테스트용으로 나누는 함수
  • KNeighborsClassifier : KNN(K 최근접 이웃) 분류 모델을 만드는 클래스
  • classification_report, accuracy_score : 모델 성능 평가 시 사용

 

예제 2) 데이터 로드 및 확인

실제로 사용할 데이터를 불러오고, 입력값과 정답값으로 나눈다.

wine = load_wine()      # Wine 데이터셋 로드
X = wine.data           # 특성 데이터
y = wine.target         # 레이블 데이터

 

  • load_wine() : 
  • wine.data : 입력 데이터
    • 각 와인의 화학 성분 정보 등이 들어 있다.
  • wine.target : 정답 데이터
    • 각 데이터가 어떤 와인 종류인지 나타내는 레이블
  • X : 문제를 풀 때 사용하는 입력값
  • y : 정답

 

* 참고 Wine Dataset

load_wine()을 실행하면 Bunch 객체 데이터 구조가 반환되며, 다음과 같은 정보가 들어있다.

항목 의미
wine.data 입력 데이터(특성, Feature)
wine.target 정답 데이터(레이블, Label)
wine.target_names 클래스 이름
wine.feature_names 특성 이름
wine.DESCR 데이터 설명

 

 

예제 3) 데이터 구조 확인

print("특성 데이터 샘플:")
print(X[:5])   # 처음 5개 데이터 확인

print("\n레이블 데이터 샘플:")
print(y[:5])   # 처음 5개 정답 확인

 

  • X[:5] : 특성 데이터의 처음 5개 행을 확인한다.
  • y[:5] : 레이블 데이터의 처음 5개 값을 확인한다.

이 과정을 통해 '입력 데이터가 숫자 형태로 잘 들어왔는지', '정답 레이블이 정상적으로 구성되었는지;' 를 확인할 수 있다.

 

즉, 모델 학습 전에 데이터 상태를 점검하는 단계이다.

 

 

예제 4) 데이터 분리

이 단계에서는 전체 데이터를 학습용과 테스트용으로 나눈다.

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

 

  • X_train, y_train : 모델을 학습시키는 데 사용하는 데이터
  • X_test, y_test : 학습이 끝난 뒤 모델 성능을 평가하는 데 사용하는 데이터
  • test_size=0.2 : 전체 데이터의 20%를 테스트용으로 사용하겠다는 의미
  • random_state=42 : 데이터를 나누는 기준을 고정하여, 실행할 때마다 같은 결과가 나오게 한다.

이는 모델이 학습한 데이터만 잘 맞추는 것이 아니라, 처음 보는 데이터도 잘 분류하는지 확인하기 위함이다.

 

 

예제 5) 데이터 분리 결과 확인  

데이터가 잘 분리되었는지 크기를 통해 확인하는 단계이다.

print("훈련 데이터 크기:", X_train.shape)
print("테스트 데이터 크기:", X_test.shape)
print("훈련 레이블 크기:", y_train.shape)
print("테스트 레이블 크기:", y_test.shape)

 

  • shape : 배열의 형태(행, 열)을 보여준다.

예를 들어 다음과 같은 것을 확인할 수 있다.

  • 훈련 데이터는 몇 개의 샘플이 있는지
  • 테스트 데이터는 몇 개의 샘플이 있는지
  • 입력과 정답의 개수가 서로 맞는지

즉, 분리된 데이터의 개수와 구조가 올바른지 검증하는 과정이다.

 

예제 5) 출력 결과

훈련 데이터 크기: (142, 13)
테스트 데이터 크기: (36, 13)
훈련 레이블 크기: (142,)
테스트 레이블 크기: (36,)

 

 

예제 6) KNN 모델 생성

이 단계에서는 KNN 모델을 만든다.

k = 3   # 가장 가까운 이웃의 개수
knn = KNeighborsClassifier(n_neighbors=k)   # KNN 분류기 생성

 

  • k=3 : 새로운 데이터를 분류할 때, 가장 가까운 3개의 이웃 데이터를 참고하겠다는 의미이다.
  • n_neighbors=k : KNN 모델에서 참고할 이웃 수를 설정한다.
  • KneighborsClassifier :  Scikit-learn에서 제공하는 KNN 기반 분류 모델을 생성하는 클래스

* 왜 K 값이 중요한가?

  • KNN은 새로운 데이터가 들어왔을 때, 주변의 가까운 데이터들을 보고 다수결로 분류한다.
  • 이때 k는 몇 개의 데이터를 볼 것인가를 정하는 값이다.
  • K 값이 너무 작을 경우, 노이즈나 이상치의 영향을 크게 받는다.
  • K 값이 너무 클 경우, 전체적인 평균 성향만 따라가 데이터의 특성이 약해진다.

 

예제 7) 모델 학습

훈련 데이터를 이용해 KNN 모델을 학습시킨다.

knn.fit(X_train, y_train)

 

  • fit(입력 데이터, 정답 데이터) : 모델이 데이터를 바탕으로 분류 기준을 갖도록 만드는 함수

KNN은 다른 모델처럼 복잡한 수식을 만들어내지 않는다.

훈련 데이터를 저장해 두고, 새로운 데이터가 들어왔을 때 가까운 이웃을 비교하는 방식에 가깝다.

 

예제 8) 모델 평가

학습된 모델이 테스트 데이터를 얼마나 잘 분류하는지 평가한다.

y_pred = knn.predict(X_test)    # 테스트 데이터 예측
accuracy = accuracy_score(y_test, y_pred)   # 정확도 계산

print(f"KNN 모델 정확도 (K={k}): {accuracy * 100:.2f}%")

 

  • predict(X_test) : 테스트 데이터에 대해 예측 결과를 생성한다.
  • accuracy_score(y_test, y_pred) : 실제 정답과 예측값이 얼마나 일치하는지 비율을 계산한다.

정확도는 가장 기본적인 평가 지표로, 전체 예측 중 맞춘 비율을 의미한다.

 

예제 8) 출력 결과

전체 테스트 데이터 중 80.56%를 올바르게 분류했다는 의미이다.

KNN 모델 정확도 (K=3): 80.56%

 

 

예제 9) 분류 성능 세부 보고서 출력

단순 정확도보다 더 자세한 분류 성능을 확인한다.

print("\n분류 성능 세부 보고서:")
print(classification_report(y_test, y_pred, target_names=wine.target_names))

 

  • classification_report() : 분류 문제에서 성능을 자세히 보여준다.
  • target_names=wine.target_names : 숫자 레이블(0,1,2) 대신 실제 클래스 이름을 출력하게 해준다.

예제 9) 출력 결과

분류 성능 세부 보고서:
              precision    recall  f1-score   support

     class_0       0.86      0.86      0.86        14
     class_1       0.92      0.79      0.85        14
     class_2       0.60      0.75      0.67         8

    accuracy                           0.81        36
   macro avg       0.79      0.80      0.79        36
weighted avg       0.82      0.81      0.81        36

 

 

  • precision(정밀도) : 모델이 특정 클래스로 예측한 것 중 실제로 맞은 비율
    • 예) class_1의 precision 값 = 0.92
      • 모델이 class_1이라고 예측한 데이터 중 92%가 실제 class_1이다.
  • recall(재현율) : 실제 해당 클래스인 데이터 중 모델이 올바르게 찾아낸 비율
    • 예) class_2 recall 값= 0.75
      • 실제 class_2 데이터 중 75%를 모델이 올바르게 분류했다는 의미이다.
  • f1-score :precision과 recall의 균형을 고려한 종합적인 성능 지표
    • class_2의 분류 성능이 상대적으로 낮음을 확인할 수 있다.
  • support : 각 클래스의 실제 데이터 개수
  • accuracy(전체 정확도) : 전체 데이터 중 올바르게 분류한 비율
  • macro avg: 각 클래스의 성능을 동일한 비중으로 평균 낸 값
    • 데이터 개수와 상관없이 각 클래스의 성능을 동일한 비중으로 평가한다.
  • weighted avg : 각 클래스 데이터 개수를 고려한 평균 값
    • 데이터 수가 많은 클래스의 영향이 더 크게 반영된다.

 

예제 10) 새로운 데이터 예측 

학습이 끝난 모델에 새로운 데이터를 넣어 어떤 클래스로 분류되는지 확인한다.

new_data = [[13.2, 2.7, 2.5, 18.0, 100.0, 2.6, 2.8, 0.3, 1.9, 5.5, 1.0, 3.2, 1050.0]]
prediction = knn.predict(new_data)
predicted_class = wine.target_names[prediction][0]

print(f"\n새로운 데이터 {new_data}의 예측 결과: {predicted_class}")

 

  • new_data : 예측하고 싶은 새로운 샘플 데이터
  • knn.predict(new_data) : 모델이 새 데이터를 보고 어떤 클래스로 분류할지 예측한다.
  • wine.target_names[prediction][0] : 예측 결과로 나온 숫자 레이블을 실제 클래스 이름으로 바꿔준다.

*target_name가 중요한 이유

모델의 예측 결과는 보통 0, 1, 2 같은 숫자로 나온다.

그런데 숫자로 보면 어떤 의미인지 바로이해하기 어렵기 때문에, 숫자 레이블을 실제 클래스 이름으로 바꾸는 과정이 필요하다.

 

 

3. K 값

KNN 알고리즘에서 K값은 매우 중요한 하이퍼파라미터이다.

K 값은 새로운 데이터를 예측할 때 참고할 이웃 데이터의 개수를 의미한다.

 

예시)

  • K =1인 경우 : 가장 가까운 하나의 데이터만 참고하여 결과를 결정한다.
  • K=3인 경우 : 가장 가까운 3개의 데이터를 참고하여 다수결로 결과를 결정한다.

 

3-1 K 값이 작을 경우

  • 장점
    • 데이터의 세부적인 패턴을 잘 반영한다.
    • 복잡한 데이터 구조를 잘 표현한다.
  • 단점
    • 노이즈 데이터에 민감하다.
    • 과적합(Overfitting) 발생이 가능하다.
    • 작은 데이터 변화에도 결과가 쉽게 바뀔 수 있다.

 

3-2 K 값이 클 경우

  • 장점
    • 노이즈의 영향을 줄일 수 있다.
    • 더 안정적인 예측이 가능하다.
  • 단점
    • 데이터의 세부적인 패턴을 반영하기 어렵다.
    • 과소적합(Underfitting) 가능성이 증가한다.

 

3-3 K 값 선택 시 고려 사항

1) 데이터 크기

데이터 개수에 따라 적절한 값이 달라질 수 있다.

 

예시)

  • 작은 데이터셋 → k 값을 작게 설정
  • 큰 데이터셋 → k 값을 크게 설정

 

2) 홀수 값 사용

분류 문제에서 클래스가 2개일 경우 k값을 홀수로 설정하는 것이 일반적이다.

 

이는 결과가 동률(Tie)이 되는 상황을 방지하기 위함이다.

 

 

3) 교차 검증(Cross Validation)

최적의 K 값을 찾기 위해 여러 값을 테스트하고 모델 성능을 비교할 수 있다.

이를 통해 과적합과 과소적합 사이의 균형을 찾을 수 있다.

 

 

4. Scikit-learn을 이용한 K 값 선택

예제 1) 라이브러리 불러오기

프로그램에 필요한 기능들을 불러오는 단계이다.

from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score

 

  • load_wine : 실습용 와인 데이터셋을 불러온다.
  • train_test_split : 전체 데이터를 학습용 데이터와 테스트 데이터로 나눈다.
  • KNeighborsClassifier : KNN(K-최근접 이웃) 분류 모델을 작성한다.
  • accuracy_score : 모델이 예측한 값이 실제 정답과 얼마나 일치하는지 정확도를 계산한다.

 

예제 2) 데이터 로드 및 입력값/정답값 분리

데이터를 불러오고, 학습용/테스트용으로 분리하는 단계이다.

wine = load_wine()

X_train, X_test, y_train, y_test = train_test_split(
    wine.data,
    wine.target,
    test_size=0.2,
    random_state=42
)

 

  • X_train, y_train : 모델을 학습시키는 데 사용하는 데이터
  • X_test, y_test : 학습이 끝난 뒤 모델 성능을 평가하는 데 사용하는 데이터
  • test_size=0.2 : 전체 데이터의 20%를 테스트용으로 사용하겠다는 의미
  • random_state=42 : 데이터를 나누는 기준을 고정하여, 실행할 때마다 같은 결과가 나오게 한다.

 

 

예제 3) K 값에 따른 정확도 비교

k 값을 바꿔가면서 KNN 모델의 성능을 비교하는 단계이다.

accuracies = {}

for k in range(1, 21):
    knn = KNeighborsClassifier(n_neighbors=k)
    knn.fit(X_train, y_train)
    y_pred = knn.predict(X_test)
    accuracy = accuracy_score(y_test, y_pred)
    accuracies[k] = accuracy

 

  1. accuracies = {}
    • 딕셔너리를 하나 만든다.
    • 이 딕셔너리는 K 값과 그때의 정확도를 저장하는 역할을 한다.
    • key : K 값
    • value : 해당 K 값에서의 정확도
  2. for k in range(1,21):
    • K 값일 1부터 20까지 하나씩 바꿔가며 반복한다.
  3. knn = KNeighborsClassifier(n_neighbors=k)
    • KNN 모델을 생성한다.
    • n_neighbors=k : 주변 이웃을 몇 개 참고할 것인가
  4. knn.fit(X_train, y_train)
    • 모델을 학습시킨다.
    • X_train : 학습용 입력 데이터
    • y_train : 학습용 정답 데이터
  5. y_pred = knn.predict(X_test)
    • 테스트 데이터를 이용해서 예측을 수행한다.
    • y_pred : 모델이 예측한 답
  6. accuracy = accuracy_score(y_test, y_pred)
    • 정확도를 계산한다.
    • y_test : 실제 정답
    • y_pred: 모델이 예측한 값
  7. accuracies[k] = accuracy
    • 현재 k 값에 대한 정확도를 딕셔너리에 저장한다.

 

range(1, 21, 2)로 설정하면 K 값을 1, 3, 5, ..., 19처럼 홀수만 사용할 수 있다.

이진 분류에서는 동률을 방지하기 위해 홀수 K 값을 사용하는 경우가 많다.

 

예제 4) 결과 출력

K 값을 바꿔가며 측정한 정확도를 출력하는 단계이다.

for k, acc in accuracies.items():
    print(f"K={k}: 정확도={acc * 100:.2f}%")

 

  • acc * 100 : 정확도를 퍼센트(%) 형태로 바꾼다.
  • :2.f : 소수점 둘째 자리까지 출력한다.

 

예제 4) 출력 결과

이 출력은 K 값을 1부터 20까지 바꿔가며 측정한 정확도를 보여준다.

K=1: 정확도=77.78%
K=2: 정확도=72.22%
K=3: 정확도=80.56%
K=4: 정확도=75.00%
K=5: 정확도=72.22%
K=6: 정확도=72.22%
K=7: 정확도=69.44%
K=8: 정확도=72.22%
K=9: 정확도=72.22%
K=10: 정확도=72.22%
K=11: 정확도=75.00%
K=12: 정확도=72.22%
K=13: 정확도=72.22%
K=14: 정확도=72.22%
K=15: 정확도=75.00%
K=16: 정확도=72.22%
K=17: 정확도=77.78%
K=18: 정확도=77.78%
K=19: 정확도=77.78%
K=20: 정확도=77.78%

 

 

예제 5) 최적의  k 값 찾기

가장 정확도가 높은 K 값을 찾는 단계이다.

best_k = max(accuracies, key=accuracies.get)
print(f"\n최적의 K 값: {best_k}, 정확도: {accuracies[best_k] * 100:.2f}%")

 

  • max(accuracies, key=accracies.get)
    • max(accuracies)하면 key 중 가장 큰 값이 나온다.
    • key=accracies.get을 사용하면 딕셔너리의 value를 기준으로 가장 큰 key를 찾게 된다

 

예제 6) 출력 결과

최적의 K 값: 3, 정확도: 80.56%

 

 

5. 모델의 성능 향상 및 하이퍼파라미터 튜닝

KNN의 성능은 여러 요소에 의해 영향을 받기 때문에 성능 향상을 위해 다음과 같은 방법을 사용할 수 있다.

 

5-1 데이터 전처리

KNN은 거리 기반 알고리즘이기 때문에, 데이터 스케일이 크게 영향을 받는다.

 

따라서 다음과 같은 전처리가 중요하다.

  • 데이터 스케일링(정규화/표준화)
  • 이상치 제거
  • 불필요한 특징 제거

 

5-2 거리 계산 방식 선택

데이터의 특성에 따라 다양한 거리 계산 방법을 사용할 수 있다.

대표적인 거리 방식은 다음과 같다.

  • 유클리드 거리(Euclidean Distance)
  • 맨해튼 거리(Manhatten Distance)
  • 민코프스키 거리(Minkowski Distance)

1) 유클리드 거리(Euclidean Distance)

  • 두 점 사이의 직선 거리를 계산하는 가장 기본적인 거리 측정 방법
  • 연속형 데이터에서 가장 많이 사용되는 거리 계산 방식

 

2) 맨해튼 거리(Manhatten Distance)

  • 각 특징 값의 차이의 절대값을 모두 더하여 계산하는 거리 방식
  • 격자형 도로 구조(Manhatten 거리)에서 이동하는 거리 계산 방식에서 유래함
  • 두 점 사이의 직선 거리가 아닌, 가로 이동 + 세로 이동 거리의 합을 계산하는 방식이다.
  • 다음과 같은 경우에 유용하다.
    • 데이터의 특정 값이 서로 독립적인 경우
    • 이상치의 영향을 줄이고 싶은 경우

 

3) 민코프스키 거리(Minkowski Distance)

  • 유클리드 거리와 맨해튼 거리를 일반화한 거리 계산 방식
  • 특정 파라미터 값에 따라 다양한 거리 계산 방식으로 사용할 수 있다.
  • 예)
    • p = 1 : 맨해튼 거리
    • p =2 : 유클리드 거리
  • 즉, 여러 거리 계산 방식을 하나의 공식으로 표현한 일반적인 형태의 거리 함수이다. 
 
 

5-3 하이퍼파라미터 튜닝

KNN에서는 다음과 같은 하이퍼파라미터를 조정할 수 있다.

K 값

거리 계산 방식

이웃 데이터 가중치

 

특히 K값을 여러 값으로 테스트하여 가장 좋은 성능을 보이는 값을 선택하는 것이 중요하다.

 

6. Scikit-learn을 이용한 모델의 성능 향상 및 하이퍼파라미터 튜닝

 

예제 1) 라이브러리 불러오기

KNN 분류 모델을 만들기 위해 필요한 도구들을 불러오는 단계이다.

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score, classification_report

 

  • load_breast_cancer
    • Scikit-learn에 기본 포함된 유방암 진단 데이터셋
  • train_test_split
    • 데이터를 훈련용과 테스트용으로 나눔
  • cross_val_score
    • 교차 검증을 통해 여러 K 값의 성능을 비교한다.
  • KNeighborsClassifier
    • KNN 분류 모델을 생성한다.
  • StandardScaler
    • 데이터의 크기 차이를 맞추기 위해 표준화한다.
  • accuracy_score
    • 모델의 정확도를 계산한다.
  • classification_report
    • precision, recall, f1-score 등을 한 번에 보여준다.

 

예제 2) 데이터 로드 및 분리

유방암 데이터를 불러오고, 입력 데이터와 정답 데이터를 나눈다.

cancer = load_breast_cancer()
X = cancer.data
y = cancer.target

 

 

예제 3) 훈련 세트와 테스트 세트 분리

전체 데이터를 훈련용과 테스트용으로 나누는 단계

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

 

  • test_size=0.2
    • 전체 데이터의 20%를 테스트용으로 사용하겠다는 의미
  • random_state=42
    • 데이터를 섞는 기준을 고정한다.
    • 실행할 때마다 같은 방식으로 분리되어 결과 재현이 쉬워진다.

 

예제 4) 데이터 스케일링 (매우 중요한 단계)

KNN은 거리 기반 알고리즘이기 때문에, 각 특성의 값 범위가 다르면 큰 값이 거리 계산에 더 큰 영향을 미친다.

따라서 데이터 스케일링이 매우 중요하다.

scaler = StandardScaler()

X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

 

  • StandardScaler()
    • StandardScaler() 데이터를 평균이 0, 표준편차가 1이 되도록 변환한다.
    • 즉, 각 특성값의 크기 차이를 줄여서 어떤 특성은 너무 크게, 어떤 특성은 너무 작게 반영되는 문제를 완화한다.
  • fit_transform(X_train)
    • 훈련 데이터의 평균과 표준편차를 구한 뒤, 그 기준으로 훈련 데이터를 변환한다.
    • X_test를 쓰지 않는 이유
      • 테스트 데이터의 정보를 미리 사용하면 공정한 평가가 아니기 때문이다.
      • 이를 데이터 누수(Data Leakage)라고 한다.
  • transform(X_test)
    • 테스트 데이터는 훈련 데이터에서 구한 기준으로만 변환해야 한다.

 

예제 5) K 값 튜닝

KNN에서 가장 중요한 하이퍼파라미터 중 하나가 K이다.

아래 코드에서는 K를 1부터 15까지 바꿔가며 어떤 값이 가장 좋은지 찾는다.

best_k = 1
best_score = 0

for k in range(1, 16):
    knn = KNeighborsClassifier(n_neighbors=k)
    scores = cross_val_score(knn, X_train_scaled, y_train, cv=5)
    mean_score = scores.mean()

    if mean_score > best_score:
        best_k = k
        best_score = mean_score

 

  • 하이퍼파라미터
    • 모델이 스스로 학습하는 값이 아니라, 사용자가 직접 정하는 값이다.
    • KNN의 대표적인 하이퍼파라미터는 n_neighbors이다
  • cross_val_score(.... cv=5)
    • 5-fold 교차 검증을 수행한다.
    • 데이터를 5개로 나눠서 4개는 학습, 1개는 검증에 쓰는 과정을 반복한다.

 

예제 6) 최적의 K 값 찾기

앞 단계에서 여러 K 값을 비교한 뒤, 가장 성능이 좋았던 K값을 출력한다.

print(f"최적의 K 값: {best_k}")
print(f"교차 검증 평균 정확도: {best_score * 100:.2f}%")

 

 

예제 7) 거리 계산 방식 변경 및 가중치 추가

최적의 K 값으로 최종 모델을 만들되, 이번에는 거리 계산 방식과 가중치 방식도 조정한다.

final_knn = KNeighborsClassifier(
    n_neighbors=best_k,
    weights='distance',
    metric='manhattan'
)

final_knn.fit(X_train_scaled, y_train)

 

  • weights='distance'
    • 가까운 이웃일수록 더 큰 영향력을 주겠다는 의미
    • 단순히 개수만 세는 것이 아니라, 거리까지 반영한다.
  • metric='manhatten'
    • 거리 계산 방식을 맨해튼 거리로 설정한다.
    • 좌표 차이의 절댓값을 더하는 방식이다.
  • fit(X_train_scaled, y_train)
    • 스케일링된 훈련 데이터를 이용해 최종 모델을 학습한다.

 

예제 8) 최적화된 모델 평가

학습이 끝난 모델을 테스트 데이터에 적용해서 예측값을 만들고, 그 예측이 얼마나 맞았는지 정확도를 계산한다.

y_pred = final_knn.predict(X_test_scaled)
accuracy = accuracy_score(y_test, y_pred)

print(f"최적화된 KNN 모델 정확도: {accuracy * 100:.2f}%")

 

 

예제 9) 세부적인 성능 보고서 출력

정확도만 보면 모델 성능을 충분히 알기 어려울 수 있다.

그래서 precision, recall, f1-score를 포함한 자세한 보고서를 출력한다.

print("\n분류 보고서:")
print(classification_report(y_test, y_pred, target_names=cancer.target_names))

 

  • classification_report() 
    • 각 클래스별 성능 지표를 정리해서 보여준다.
  • target_names=cancer.target_names
    • 숫자 레이블 대신 실제 클래스 이름을 보여준다.

 

예제 10) 새로운 데이터 예측

학습이 끝난 모델을 이용해 새로운 환자 데이터가 들어왔을 때 어떤 클래스로 분류되는지 예측한다.

new_data = [[14.0, 20.0, 90.0, 600.0, 0.10, 0.15, 0.12, 0.08, 0.18, 0.06,
             0.50, 1.20, 3.50, 40.0, 0.005, 0.02, 0.03, 0.01, 0.02, 0.003,
             16.0, 25.0, 105.0, 750.0, 0.14, 0.30, 0.35, 0.15, 0.28, 0.09]]

new_data_scaled = scaler.transform(new_data)
prediction = final_knn.predict(new_data_scaled)

predicted_class = cancer.target_names[prediction][0]
print(f"\n새로운 데이터의 예측 결과: {predicted_class}")

 

  • new_data : 실제로 예측하고 싶은 새로운 입력값
  • scaler.transform(new_data) : 새 데이터도 반드시 훈련 데이터와 같은 기준으로 스케일링해야 한다.
  • predict(new_data_scaled) : 새 데이터의 클래스 예측
  • cancer.target_names[prediction][0] : 숫자로 나온 결과를 실제 클래스 이름으로 바꿔준다.

 


👉 머신러닝 & 딥러닝 기초 23편 | 비지도학습 - 군집화(Clustering)