최근접 이웃
최근접 이웃 알고리즘은 예측하려고 하는 임의의 데이터와 가장 가까운 거리의 데이터 K개를 찾아 다수결에 의해 데이터를 예측하는 방법이다. 그룹으로 나뉜 데이터가 있을 때 주어진 임의의 데이터가 어느 그룹에 속할 것인지를 K-NN 알고리즘으로 풀 수 있다.
임의의 데이터로부터 가장 가까운 K개 데이터들이 더 많이 속한 그룹으로 임의의 데이터를 분류하는 알고리즘이다. 만약 K가 3이라면 3개의 데이터를 확인하여 더 많은 데이터가 있는 그룹으로 임의의 데이터를 분류한다. K의 선택 기준은 학습의 난이도와 데이터의 개수이며, 보통 훈련 데이터 개수의 제곱근으로 설정한다.
K와 임의의 데이터 간 좌표상 거리도 고려해야 한다. K를 4로 설정했다면, 4개의 데이터 중 하나의 데이터가 거리가 가장 멀다면 가중치가 가장 낮으므로 다른 그룹으로 분류된다.
K-NN의 장점
- 추가된 데이터의 처리가 쉽다.
- 예측 결과에 대한 해석이 쉽다.
- 사용이 간단하여 훈련 데이터에 대한 훈련 과정이 별도로 필요하지 않다.
- 범주를 나눈 기준을 알지 못 하더라도 데이터를 분류할 수 있다.
K-NN의 단점
- 훈련 데이터셋의 크기가 너무 크거나 특성(feature)의 개수가 너무 많으면 연산속도가 느려진다.
- 비수치 데이터의 유사도를 정의하기 어렵고 이상치의 영향을 크게 받는다.
- 서로 다른 특성 값들의 비율을 일정하게 하지 않을 경우 성능이 떨어지므로 같은 스케일을 갖도록 전처리하는 과정이 필요하다.
K값이 너무 작으면?
거리가 가장 가까운 데이터 1개를 기준으로 삼아 새로운 데이터를 분류하게 되므로 분류 기준이 매우 엄격해진다. 훈련 데이터셋에 대해서는 높은 정확도를 기대할 수 있지만 새로운 데이터들에 대해서는 높은 정확도를 기대하기 어렵다. 과대적합 문제가 발생할 수 있다.
K값이 너무 크면?
거리가 가장 가까운 K개의 모든 데이터를 기준으로 데이터를 분류하기 때문에 모델의 분류 기준이 매우 모호해진다. 과소적합 문제가 빌생할 수 있다.
따라서 적절한 K의 개수를 정하는 것이 매우 중요하다. 일반적으로 K-NN 분류 모델을 훈련시킬 때 일정 범주를 주고 학습을 시키며, 교차검증이나 리샘플링 기법을 이용하여 최적의 성능을 내는 K값을 구한다.
Library Import
1
2
3
4
5
6
7
8
9
| import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import confusion_matrix, classification_report
|
Dataset
1
2
| df = pd.read_csv('C:/Users/USER/Desktop/Data/diabetes.csv')
df.head()
|
| Pregnancies | Glucose | BloodPressure | SkinThickness | Insulin | BMI | DiabetesPedigreeFunction | Age | Outcome |
---|
0 | 6 | 148 | 72 | 35 | 0 | 33.6 | 0.627 | 50 | 1 |
---|
1 | 1 | 85 | 66 | 29 | 0 | 26.6 | 0.351 | 31 | 0 |
---|
2 | 8 | 183 | 64 | 0 | 0 | 23.3 | 0.672 | 32 | 1 |
---|
3 | 1 | 89 | 66 | 23 | 94 | 28.1 | 0.167 | 21 | 0 |
---|
4 | 0 | 137 | 40 | 35 | 168 | 43.1 | 2.288 | 33 | 1 |
---|
Scaling
1
2
| scale = StandardScaler()
x_scaled = scale.fit_transform(df.iloc[:, :-1])
|
Data Split
suffle
: 데이터를 순서대로 사용할지, 섞어서 사용할지stratify
: label의 분포 비율
1
| X_train, X_test, y_train, y_test = train_test_split(x_scaled, y, test_size=0.4, random_state=42, stratify=y)
|
K값을 변경하며 정확도 측정
1
| from sklearn.neighbors import KNeighborsClassifier
|
1
2
3
4
5
6
7
8
9
10
| neighbors = np.arange(1, 9) # 1 ~ 8
train_accuracy = np.empty(len(neighbors))
test_accuracy = np.empty(len(neighbors))
for i, k in enumerate(neighbors): # i(0~7), k(1~8)
knn = KNeighborsClassifier(n_neighbors=k)
knn.fit(X_train, y_train)
train_accuracy[i] = knn.score(X_train, y_train)
test_accuracy[i] = knn.score(X_test, y_test)
|
1
2
3
4
5
6
7
8
9
10
11
| plt.style.use('ggplot')
plt.plot(train_accuracy, label='Training Accuracy')
plt.plot(test_accuracy, label='Testing Accuracy')
plt.title('K-NN Varing nunber of neighbors')
plt.xlabel('K')
plt.ylabel('Accuracy')
plt.legend()
plt.show()
|
K-NN
K 값을 결정하기 위한 위 그래프에서 train과 test의 정확도 차이가 젤 적게 나온 k=7을 사용한다.
1
2
3
| knn = KNeighborsClassifier(n_neighbors=7)
knn.fit(X_train, y_train)
pred = knn.predict(X_test)
|
혼동행렬
1
| confusion_matrix(y_test, pred)
|
1
2
| array([[169, 32],
[ 46, 61]], dtype=int64)
|
1
| pd.crosstab(y_test, pred, rownames=['True'], colnames=['Predict'], margins=True)
|
Predict | 0 | 1 | All |
---|
True | | | |
---|
0 | 169 | 32 | 201 |
---|
1 | 46 | 61 | 107 |
---|
All | 215 | 93 | 308 |
---|
1
| print(classification_report(y_test, pred))
|
1
2
3
4
5
6
7
8
| precision recall f1-score support
0 0.79 0.84 0.81 201
1 0.66 0.57 0.61 107
accuracy 0.75 308
macro avg 0.72 0.71 0.71 308
weighted avg 0.74 0.75 0.74 308
|
민코프스키 공식을 이용한 K-NN 거리 측정
최근접 이웃 알고리즘에서 사용되는 데이터 간 거리를 구하는 방식에는 맨해튼
과 유클리드
측정 방식이 있다. 맨해튼 거리 측정 방식은 두 점 사이 격자를 고려한 방식이고, 유클리드 거리 측정 방식은 최단거리를 측정한 것이다.
파이썬의 KNeighborsClassifier 함수에서 인자 값을 생략할 경우, 민코프스키에 P=2(유클리드 거리)가 기본값으로 설정되어 있다. P=1이면 맨해튼 거리를 계산한다.