Data Science/데이터 분석 📊

[데이터 분석] 13. 최근접 이웃(k Nearest Neighbor)

SLYK1D 2024. 8. 4. 16:32
728x90
반응형

1. 분류

본격적으로 분류와 관련된 알고리즘을 알아보기에 앞서 분류라는 것에 대한 정의를 간략하게 짚고 넘어가고자 한다. 분류새롭게 나타난 현상에 대해서 기존이 나눠둔, 혹은 정의된 집합에 배정하는 것을 의미한다. 주로 반응변수(종속변수)가 알려진 다변량 자료를 이용해 모형을 구축하고 이를 통해 새로운 자료에 대한 예측 및 분류를 수행하는 것이 목적이다. 반응 변수가 범주형인 경우에는 분류, 연속형인 경우에는 예측이라 한다. 대표적인 알고리즘으로는 앞쪽에서 살펴본 로지스틱 회귀 부터, 의사결정나무, 서포트벡터, 랜덤 포레스트 등이 있다.
로지스틱 회귀의 경우 회귀 부분에서 언급했기 때문에 이번에는 넘어가도록 하겠다.

2. kNN(k Nearest Neighbor)

이번 장에서는 분류와 관련된 머신러닝 알고리즘들 중에서 가장 단순한 모델인 kNN(k Nearest Neighbor, 최근접 이웃)에 대해서 다뤄볼 것이다. 이름에서도 알 수 있듯이, kNN 은 임의의 데이터를 기준으로 주변에 분포하는 이웃 데이터 k 개의 속성을 참조해 데이터를 분류 예측하는 방식을 사용한다. 

2.1 kNN의 특징

다음으로 kNN 알고리즘의 장단점, 동작 방식 등을 통해 kNN 이 갖는 특징에 대해 살펴보도록 하자. 앞서 간략하게 이야기 했지만, kNN 알고리즘은 주변에 분포하는 데이터들의 속성을 이용하며, 만약 새로운 데이터가 들어오면, 해당 데이터를 중심으로 주변 데이터의 레이블(혹은 클래스) 의 빈도를 측정해 가장 빈도가 높은 레이블로 분류하는 방식이다. 때문에 알고리즘이 다른 분류 모델들에 비해 동작 원리가 단순하고, 간단하기에 훈련 속도가 빠른 편에 속하고, 적은 데이터를 사용해도 분류 정확도가 높다는 장점을 가진다. 
하지만, 만약 주변에 위치한 데이터가 이상치이거나, 노이즈가 심한 경우라면 분류 정확도에 영향을 줄 수 있고, 모든 데이터에 대해 기억을 해야되기 때문에 데이터가 많을 수록 메모리 사용률이 높으며, 계산복잡도가 높아질 수 있다는 단점이 존재한다. 
위와 같은 이유로, 보통은 적은 데이터를 이용하여 분류 예측하는 경우에 효과적이며, 사용하기에 따라 데이터 내의 이상치 유무나 노이즈 존재를 파악하는 용도로도 활용할 수 있다. 

또 다른 특징으로는 거리 기반의 분류모델이라는 점이다. 위의 그림을 통해서 알 수 있듯이, 이웃의 개수를 파악하는 방법은 특정 갯수별 원이 그려진 것을 알 수 있다. 즉, 중심이 되는 데이터로부터 다른 데이터들 간의 거리를 측정해 k 개에 맞는 데이터를 파악하는 것이라고 할 수 있다. 이처럼 거리를 기반으로 하는 알고리즘 이기 때문에 상대적으로 짧은 거리에 있는 데이터를 이웃으로 판단하며, 이들의 레이블 빈도를 파악해 가장 빈도가 높은 레이블(클래스)로 분류하는 알고리즘이다. 

2.2 거리 측정 방법

그렇다면 거리를 측정을 하기 위한 방식들을 알아보도록 하자. 거리를 측정하는 방식에는 여러가지 방법론 및 함수들이 존재하지만, 이번 장에서는 가장 많이 사용되는 측정 방법 4가지에 대해서 다뤄볼 예정이다. 

2.2.1 유클리드 거리

첫 번째로 알아볼 거리측정법은 우리에게 가장 친숙한 방법인 유클리드 거리(Euclidean Distance) 이다. 주로 두 점 사이의 거리를 측정할 때 사용하는 방법으로 수식으로 표현하면 다음과 같다. 

$$d(p, q) = d(q, p) = \sqrt{(q_1 - p_1)^2 + (q_2 - p_2)^2 + ... + (q_n - p_n)^2}$$
$$ = \sqrt{\sum_{i=1}{n}(q_i - p_i)^2}$$

2.2.2 멘하튼 거리

두 번째로 알아볼 방법은 멘하튼 거리(Manhatten Distance) 이다. 한 지점에서 다른 지점으로 이동할 때, x 축과 y 축을 아래 그림과 같이 격자에 맞춰서 이동하는 거리를 측정하는 방식이며, 어떤 경로로 이동하든 결과적으로는 동일하다는 것을 알 수 있다. 수식으로 표현하자면, 다음과 같이 할 수 있다. 

$$d(X, Y) =  \sum_{i=1}{n}|x_i - y_i|$$

2.2.3 마할라노비스 거리

다음으로는 마할라노비스 거리(Mahalanobis Distance) 인데, 각 변수의 분산과 공분산을 고려하여 상관관계를 고려해 거리를 측정하는 방식이다. 주로 이상탐지를 하는 경우에 활용된다. 수식으로 표현하면 다음과 같이 나타낼 수 있다.

$$d(X, Y) = \sqrt{(\vec{X} - \vec{Y})^T \sum{}{-1}(\vec{X} - \vec{Y})}$$

2.2.4 해밍 거리

마지막으로 해밍 거리(Hamming Distance) 에 대해 살펴보도록 하자. 이는 같은 크기를 갖는 데이터들을 놓고, 같은 위치에 있는 값들끼리 비교해 서로 다른 값이 있을 경우 1씩 증가시킨다. 주로 유사도를 측정할 때 활용되며, 위에서 말한 같은 위치라 함은 아래 예시에서처럼 순서상의 위치를 의미한다.

ex1. '1011101'과 '1001001'사이의 해밍 거리는 2이다. (1011101, 1001001)
ex2. '2143896'과 '2233796'사이의 해밍 거리는 3이다. (2143896, 2233796)
ex3. "toned"와 "roses"사이의 해밍 거리는 3이다. (toned, roses)

3. 실습: 유방암 진찰 데이터

마지막으로 유방암 진찰 데이터를 통해 kNN 알고리즘으로 분류하는 실습을 해보자. 코드는 Python, R 순서로 배치하니, 참고하기 바란다. 시작에 앞서, 이번 실습에서 사용되는 유방암 진찰 데이터는 아래 링크에서 다운로드 받을 수 있으며, 데이터 셋의 구성은 다음과 같다. 

https://archive.ics.uci.edu/dataset/17/breast+cancer+wisconsin+diagnostic

 

UCI Machine Learning Repository

This dataset is licensed under a Creative Commons Attribution 4.0 International (CC BY 4.0) license. This allows for the sharing and adaptation of the datasets for any purpose, provided that the appropriate credit is given.

archive.ics.uci.edu

변수명 설명
ID 식별자
Diagnosis 진단여부 (양성: B / 악성: M)
radius 반지름
texture 텍스처
perimeter 둘레
area 면적
smoothness 평활도
compactness 다짐도
concavity 요면
concave points 요면점
symmetry 대칭
fractal dimension 프렉탈 차원

먼저 실습에 필요한 데이터를 불러오고, 모델을 사용하기 전에 필요한 준비(데이터 전처리, 학습/테스트 데이터 분리 등)를 진행해보자. 

import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
import scipy.stats as stats

# 1. 사용 데이터 로드
cancer_data = pd.read_csv("~/workspace/Python3/DataAnalysis/Dataset/breast_cancer/wdbc.data", header=None)
cancer = cancer_data.iloc[:, 0:12]
cancer.columns = ["id", "diagnosis", "radius", "texture", "perimeter", \
      "area", "smoothness", "compactness", "concavity", \
      "concave_points", "symmetry", "fractal_dimension"]

print(cancer['diagnosis'].value_counts())

# 2. 원본 전처리
cancer['diagnosis'] = cancer['diagnosis'].map({'B': 0, 'M': 1})

print(round(cancer['diagnosis'].value_counts(normalize=True) * 100, 1))
print(cancer.describe())

[실행결과]
diagnosis
B    357
M    212
Name: count, dtype: int64
diagnosis
0    62.7
1    37.3
Name: proportion, dtype: float64
                 id   diagnosis  ...    symmetry  fractal_dimension
count  5.690000e+02  569.000000  ...  569.000000         569.000000
mean   3.037183e+07    0.372583  ...    0.181162           0.062798
std    1.250206e+08    0.483918  ...    0.027414           0.007060
min    8.670000e+03    0.000000  ...    0.106000           0.049960
25%    8.692180e+05    0.000000  ...    0.161900           0.057700
50%    9.060240e+05    0.000000  ...    0.179200           0.061540
75%    8.813129e+06    1.000000  ...    0.195700           0.066120
max    9.113205e+08    1.000000  ...    0.304000           0.097440
[8 rows x 12 columns]
setwd("D:/workspace/R/workspace")

cancer_data <- read.csv("Data/breast_cancer/wdbc.data", header=FALSE, sep=",", stringsAsFactors=FALSE)
cancer <- cancer_data[, 1:12]

colnames(cancer) <- c("id", "diagnosis", "radius", "texture", "perimeter", 
  "area", "smoothness", "compactness", "concavity", 
  "concave_points", "symmetry", "fractal_dimension"
)

table(cancer$diagnosis)

cancer$diagnosis <- factor(cancer$diagnosis, 
	levels = c("B","M"), 
    labels = c("Benign", "Malignant")
)

round(prop.table(table(cancer$diagnosis)) * 100, digits = 1)

summary(cancer)

[실행결과]
  B   M 
357 212 

Benign Malignant 
 62.7      37.3 

       id                diagnosis       radius          texture        perimeter     
 Min.   :     8670   Benign   :357   Min.   : 6.981   Min.   : 9.71   Min.   : 43.79  
 1st Qu.:   869218   Malignant:212   1st Qu.:11.700   1st Qu.:16.17   1st Qu.: 75.17  
 Median :   906024                   Median :13.370   Median :18.84   Median : 86.24  
 Mean   : 30371831                   Mean   :14.127   Mean   :19.29   Mean   : 91.97  
 3rd Qu.:  8813129                   3rd Qu.:15.780   3rd Qu.:21.80   3rd Qu.:104.10  
 Max.   :911320502                   Max.   :28.110   Max.   :39.28   Max.   :188.50  
      area          smoothness       compactness        concavity       concave_points   
 Min.   : 143.5   Min.   :0.05263   Min.   :0.01938   Min.   :0.00000   Min.   :0.00000  
 1st Qu.: 420.3   1st Qu.:0.08637   1st Qu.:0.06492   1st Qu.:0.02956   1st Qu.:0.02031  
 Median : 551.1   Median :0.09587   Median :0.09263   Median :0.06154   Median :0.03350  
 Mean   : 654.9   Mean   :0.09636   Mean   :0.10434   Mean   :0.08880   Mean   :0.04892  
 3rd Qu.: 782.7   3rd Qu.:0.10530   3rd Qu.:0.13040   3rd Qu.:0.13070   3rd Qu.:0.07400  
 Max.   :2501.0   Max.   :0.16340   Max.   :0.34540   Max.   :0.42680   Max.   :0.20120  
    symmetry      fractal_dimension
 Min.   :0.1060   Min.   :0.04996  
 1st Qu.:0.1619   1st Qu.:0.05770  
 Median :0.1792   Median :0.06154  
 Mean   :0.1812   Mean   :0.06280  
 3rd Qu.:0.1957   3rd Qu.:0.06612  
 Max.   :0.3040   Max.   :0.09744

위의 코드를 실행하면 알 수 있듯이, 각 변수별로 측정범위가 다르기 때문에 값을 재조정하여 일정 범위의 값으로 변경해준다. 다음으로 모델이 원활히 학습이 진행되도록 학습 데이터와 테스트 데이터를 분할한다. 비율은 약 8:2 정도로 설정했다. 분류결과 역시 동일한 비율로 학습용과 테스트용으로 분류한다.

# 데이터셋 분리
cancer_data = cancer[["id", "radius", "texture", "perimeter", "area", "smoothness", "compactness", "concavity", "concave_points", "symmetry", "fractal_dimension"]]
cancer_label = cancer[["diagnosis"]]
x_train, x_test, y_train, y_test = train_test_split(cancer_data, cancer_label, test_size=0.2, random_state=1234)
train <- cancer[1:469, c(1, 3:12)]
test <- cancer[470:569, c(1, 3:12)]

train_label <- cancer[1:469, 2]
test_label <- cancer[470:569, 2]

데이터 분할까지 완료했으니, 이제 모델링을 진행해보도록 하자. R의 경우에는 class 패키지에 포함되어있는 knn() 함수를 사용하면 되고, 매개변수는 아래 설명과 같다. 

model <- knn(train, test, class, k)

* train : 수치형 데이터로 구성된 학습용 데이터 셋
* test : 수치형 데이터로 구성된 테스트용 데이터 셋
* class : 훈련 데이터의 각 행에 대응되는 범주형 데이터로 구성된 라벨
* k : 최근접 이웃의 개수 , 정수형으로 명시
  - 선정 : k^2 이 학습 데이터의 행의 개수에 근접하도록 설정한다.

위의 데이터로 모델을 학습하는 과정은 다음과 같다. 

knn = KNeighborsClassifier(n_neighbors=21)
knn.fit(x_train, y_train)
y_pred = knn.predict(x_test)
print(y_pred)

[실행결과]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
install.packages("class")
library(class)

y_pred <- knn(train = train, test = test, cl = train_label, k = 21)
print(y_pred)

[실행결과]
  [1] Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign
 [14] Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign
 [27] Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign
 [40] Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign
 [53] Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign
 [66] Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign
 [79] Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign Benign
 [92] Benign Benign Benign Benign Benign Benign Benign Benign Benign
Levels: Benign Malignant

다음으로 생성한 분류 모델에 대한 성능평가방법은 여러가지가 있는데 이번 장에서는 교차표(CrossTable)을 사용한 성능평가를 진행해볼 것이다. R의 경우에는 gmodels 패키지에 있는 CrossTable() 함수를 사용하면 되며, 사용방법은 아래 예시와 같이 사용하면 된다. 참고로 교차표에 관한 내용은 추후 모델 성능평가와 관련된 내용에서 설명할 예정이니, 이번 장에서는 간단하게 이런 기법이 있다 정도로만 이해하면 될 것이다. 

conf_matrix = confusion_matrix(y_test, y_pred)
print(conf_matrix)

[실행결과]
[[65  4]
 [37  8]]
install.packages("gmodels")
library(gmodels)

CrossTable(x = test_label, y = test_pred, prop.chisq = F)

[실행결과]

	Cell Contents
|-------------------------|
|                       N |
|         N / Table Total |
|-------------------------|

 
Total Observations in Table:  100 

 
             | y_pred 
  test_label |    Benign | Row Total | 
-------------|-----------|-----------|
      Benign |        77 |        77 | 
             |     0.770 |           | 
-------------|-----------|-----------|
   Malignant |        23 |        23 | 
             |     0.230 |           | 
-------------|-----------|-----------|
Column Total |       100 |       100 | 
-------------|-----------|-----------|

코드를 실행하면 아래 그림과 유사한 형태의 결과가 나올 것이다. 뒤에서 자세히 설명하겠지만, 현재 우리가 사용 중인 분류는 이진분류에 해당하며, 클래스가 2개이기 때문에 교차표에서 모델이 정확하게 분류한 부분은 TP(True Positive), TN(True Negative) 에 해당한다. 이를 그림으로 표현한 것이 아래의 그림이다. 

위의 내용을 통해 결과를 해석해보자면, 전체 100개 중 77개를 정확히 골라냈다는 것까지 확인할 수 있다. 추가적으로 위의 실행결과는 1개 클래스로만 분류했다는 것을 통해 학습이 원활히 진행되지 않았다는 것도 알 수 있다. 
끝으로 모델의 개선방법에 대해서 살펴보고 마무리 하겠다. 위의 모델이 77%의 정확도를 갖는다고 할 수 있지만, 1개 클래스로만 분류가 되었으며, 실무에서 위와 같은 상황 나오면 안된다. 그렇다면 모델에 변화를 주거나 데이터에 변화를 주는 것이 일반적이며, 먼저 데이터에 대한 변화를 살펴보려고 한다. 데이터에 대해 변화를 주는 경우는 데이터의 크기나 전처리를 추가로 하는 방법 등이 있으며, 이번 장에서는 Z-score 표준화라는 작업을 진행할 것이다. Z-score 는 표준화된 값은 최소와 최대를 미리 정하지 않았기 때문에 극단적으로 값이 중앙에 모이지 않으며, 때문에 거리 계산에서 이상치에 좀 더 큰 가중치를 주는 것이 합리적이라고 판단한다.

# 성능개선
# 1. 데이터 전처리 추가
scaler = StandardScaler()
cancer_z = scaler.fit_transform(cancer[['radius', 'texture', 'perimeter', 'area', 'smoothness', 'compactness', 'concavity', 'concave_points', 'symmetry', 'fractal_dimension']])
cancer_z = pd.DataFrame(cancer_z, columns=['radius', 'texture', 'perimeter', 'area', 'smoothness', 'compactness', 'concavity', 'concave_points', 'symmetry', 'fractal_dimension'])
cancer_z = pd.concat([cancer["id"], cancer_z], axis=1)

x_train, x_test, y_train, y_test = train_test_split(cancer_z, cancer_label, test_size=0.2, random_state=1234)

knn.fit(x_train, y_train)
y_pred = knn.predict(x_test)
print(confusion_matrix(y_test, y_pred))

[실행결과]
[[65  4]
 [37  8]]
cancer_z <- as.data.frame(scale(cancer[, c(1, 3:12)], center=TRUE, scale=TRUE))
summary(cancer_z)

train_z <- cancer_z[1:469,]
test_z <- cancer_z[470:569,]

test_z_pred <- knn(train_z, test_z, cl = train_label, k=21)

CrossTable(x = test_label, y = test_z_pred, prop.chisq = F)

[실행결과]
      id              radius           texture          perimeter            area        
 Min.   :-0.2429   Min.   :-2.0279   Min.   :-2.2273   Min.   :-1.9828   Min.   :-1.4532  
 1st Qu.:-0.2360   1st Qu.:-0.6888   1st Qu.:-0.7253   1st Qu.:-0.6913   1st Qu.:-0.6666  
 Median :-0.2357   Median :-0.2149   Median :-0.1045   Median :-0.2358   Median :-0.2949  
 Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000  
 3rd Qu.:-0.1724   3rd Qu.: 0.4690   3rd Qu.: 0.5837   3rd Qu.: 0.4992   3rd Qu.: 0.3632  
 Max.   : 7.0464   Max.   : 3.9678   Max.   : 4.6478   Max.   : 3.9726   Max.   : 5.2459  
   smoothness        compactness        concavity       concave_points       symmetry       
 Min.   :-3.10935   Min.   :-1.6087   Min.   :-1.1139   Min.   :-1.2607   Min.   :-2.74171  
 1st Qu.:-0.71034   1st Qu.:-0.7464   1st Qu.:-0.7431   1st Qu.:-0.7373   1st Qu.:-0.70262  
 Median :-0.03486   Median :-0.2217   Median :-0.3419   Median :-0.3974   Median :-0.07156  
 Mean   : 0.00000   Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.00000  
 3rd Qu.: 0.63564   3rd Qu.: 0.4934   3rd Qu.: 0.5256   3rd Qu.: 0.6464   3rd Qu.: 0.53031  
 Max.   : 4.76672   Max.   : 4.5644   Max.   : 4.2399   Max.   : 3.9245   Max.   : 4.48081  
 fractal_dimension
 Min.   :-1.8183  
 1st Qu.:-0.7220  
 Median :-0.1781  
 Mean   : 0.0000  
 3rd Qu.: 0.4706  
 Max.   : 4.9066  
 
 
   Cell Contents
|-------------------------|
|                       N |
|           N / Row Total |
|           N / Col Total |
|         N / Table Total |
|-------------------------|

 
Total Observations in Table:  100 

 
             | test_z_pred 
  test_label |    Benign | Malignant | Row Total | 
-------------|-----------|-----------|-----------|
      Benign |        71 |         6 |        77 | 
             |     0.922 |     0.078 |     0.770 | 
             |     0.986 |     0.214 |           | 
             |     0.710 |     0.060 |           | 
-------------|-----------|-----------|-----------|
   Malignant |         1 |        22 |        23 | 
             |     0.043 |     0.957 |     0.230 | 
             |     0.014 |     0.786 |           | 
             |     0.010 |     0.220 |           | 
-------------|-----------|-----------|-----------|
Column Total |        72 |        28 |       100 | 
             |     0.720 |     0.280 |           | 
-------------|-----------|-----------|-----------|

데이터에 대한 변화를 줌으로써, 실제 결과에서 나타나듯이, 93%로 정확도가 더 증가했다는 것을 확인할 수 있다. 이처럼 데이터를 변화시켰음에도 성능 개선이 안된다면, 모델의 파라미터를 적절한 값으로 변경해주는 작업이 필요하다. kNN 의 경우 모델을 생성하는 과정에서 가장 중요한 값인 k 값을 설정할 수 있고, 이 때 최적의 k 값을 찾아내는 것이 중요하다. 일반적으로는 적절한 k 값이라고 평가되는  범위는 3 ~10 사이의 값으로 지정된다고 한다.

아래 예시에서는 1, 5, 11, 15, 21, 27 일 경우에 각각의 모델에 대한 성능을 표시한 것이다. 

k=1
[[49 20]
 [27 18]]

k=5
[[58 11]
 [34 11]]

k=11
[[59 10]
 [34 11]]

k=15
[[63  6]
 [36  9]]

k=21
[[65  4]
 [37  8]]

k=27
[[65  4]
 [37  8]]

 

# 모델 내 파라미터(K 값) 변경
# k = 1
Total Observations in Table:  100 

 
             | y_pred 
  test_label |    Benign | Malignant | Row Total | 
-------------|-----------|-----------|-----------|
      Benign |        69 |         8 |        77 | 
             |     0.896 |     0.104 |     0.770 | 
             |     0.986 |     0.267 |           | 
             |     0.690 |     0.080 |           | 
-------------|-----------|-----------|-----------|
   Malignant |         1 |        22 |        23 | 
             |     0.043 |     0.957 |     0.230 | 
             |     0.014 |     0.733 |           | 
             |     0.010 |     0.220 |           | 
-------------|-----------|-----------|-----------|
Column Total |        70 |        30 |       100 | 
             |     0.700 |     0.300 |           | 
-------------|-----------|-----------|-----------|

# k = 5
             | y_pred 
  test_label |    Benign | Malignant | Row Total | 
-------------|-----------|-----------|-----------|
      Benign |        70 |         7 |        77 | 
             |     0.909 |     0.091 |     0.770 | 
             |     1.000 |     0.233 |           | 
             |     0.700 |     0.070 |           | 
-------------|-----------|-----------|-----------|
   Malignant |         0 |        23 |        23 | 
             |     0.000 |     1.000 |     0.230 | 
             |     0.000 |     0.767 |           | 
             |     0.000 |     0.230 |           | 
-------------|-----------|-----------|-----------|
Column Total |        70 |        30 |       100 | 
             |     0.700 |     0.300 |           | 
-------------|-----------|-----------|-----------|

# k = 11
             | y_pred 
  test_label |    Benign | Malignant | Row Total | 
-------------|-----------|-----------|-----------|
      Benign |        69 |         8 |        77 | 
             |     0.896 |     0.104 |     0.770 | 
             |     0.986 |     0.267 |           | 
             |     0.690 |     0.080 |           | 
-------------|-----------|-----------|-----------|
   Malignant |         1 |        22 |        23 | 
             |     0.043 |     0.957 |     0.230 | 
             |     0.014 |     0.733 |           | 
             |     0.010 |     0.220 |           | 
-------------|-----------|-----------|-----------|
Column Total |        70 |        30 |       100 | 
             |     0.700 |     0.300 |           | 
-------------|-----------|-----------|-----------|

# k = 15
             | y_pred 
  test_label |    Benign | Malignant | Row Total | 
-------------|-----------|-----------|-----------|
      Benign |        72 |         5 |        77 | 
             |     0.935 |     0.065 |     0.770 | 
             |     0.986 |     0.185 |           | 
             |     0.720 |     0.050 |           | 
-------------|-----------|-----------|-----------|
   Malignant |         1 |        22 |        23 | 
             |     0.043 |     0.957 |     0.230 | 
             |     0.014 |     0.815 |           | 
             |     0.010 |     0.220 |           | 
-------------|-----------|-----------|-----------|
Column Total |        73 |        27 |       100 | 
             |     0.730 |     0.270 |           | 
-------------|-----------|-----------|-----------|

# k = 21
             | y_pred 
  test_label |    Benign | Malignant | Row Total | 
-------------|-----------|-----------|-----------|
      Benign |        71 |         6 |        77 | 
             |     0.922 |     0.078 |     0.770 | 
             |     0.986 |     0.214 |           | 
             |     0.710 |     0.060 |           | 
-------------|-----------|-----------|-----------|
   Malignant |         1 |        22 |        23 | 
             |     0.043 |     0.957 |     0.230 | 
             |     0.014 |     0.786 |           | 
             |     0.010 |     0.220 |           | 
-------------|-----------|-----------|-----------|
Column Total |        72 |        28 |       100 | 
             |     0.720 |     0.280 |           | 
-------------|-----------|-----------|-----------|

# k = 27
             | y_pred 
  test_label |    Benign | Malignant | Row Total | 
-------------|-----------|-----------|-----------|
      Benign |        73 |         4 |        77 | 
             |     0.948 |     0.052 |     0.770 | 
             |     0.973 |     0.160 |           | 
             |     0.730 |     0.040 |           | 
-------------|-----------|-----------|-----------|
   Malignant |         2 |        21 |        23 | 
             |     0.087 |     0.913 |     0.230 | 
             |     0.027 |     0.840 |           | 
             |     0.020 |     0.210 |           | 
-------------|-----------|-----------|-----------|
Column Total |        75 |        25 |       100 | 
             |     0.750 |     0.250 |           | 
-------------|-----------|-----------|-----------|

위의 결과를 확인해보면, 실험한 모델들 중 k=15 인 경우와 k=27 인 경우에 분류 정확도가 높은 것을 확인할 수 있다. 전체적인 숫자는 동일하지만 세부적으로 비교해보자면, 일부 분류하기 어려운 데이터가 있다는 것도 확인이 가능하다. 

728x90
반응형