Py) ML - k-최근접 이웃(kNN)

Py) ML - k-최근접 이웃(kNN)

Python에서 k-최근접이웃(k-Nearist Neighbor) 분석을 하는 방법을 알아보자.

※ 본 내용에서 사용하는 model_classification_machine_failure.csv, model_regression_ins_charges.csv 파일은 별도로 다운로드 받아야 한다.
model_classification_machine_failure.csv 다운받기 [클릭]
model_regression_ins_charges.csv 다운받기 [클릭]

이론

공통

대표적인 머신러닝 지도학습 모델인 k-NN은 k-Nearest Neighbor의 줄임말이며 k-최근접 이웃이라고 한다. 여기서 k는 k-Means Clustering(k-평균 군집법)과 같이 자연수 k인데 k는 특정 데이터를 기준으로 인접 데이터 k개를 고려한다는 뜻이다. 여기서 인접 데이터는 가장 가까이 있는 것 부터 고려하게 되는데 그래서 이웃(Neighbor)이라는 단어를 사용하여 이 알고리즘을 명명한 것 같다.

k-NN에는 여러 파라미터가 있지만 그 중 이웃 데이터 포인트 개수인 k가 가장 중요한 파라미터이다. k값은 1에 가까울수록 과적합(over fitting)이 되며 큰 값의 경우 과소적합(under fitting)이 된다. 그래서 k값을 조정하며 값을 찾는 것이 중요하다. 그렇다고 무조건 작은 k가 좋은 것은 아니며 데이터의 특성에 따라 적절한 k값을 찾아야 한다.

본 알고리즘 관련 상세 이론은 별도의 게시글에서 다룰 예정이다.

분류 모델

분류를 위해 사용되는 모델이며 종속변수에 2개 이상의 범주가 있는 경우에 사용한다. 이 때 각 범주는 0부터 1씩 증가하는 등차수열의 정수로 표현하는 것을 권장한다.

k-NN 분류모델을 구현하기 위해서는 sklearn 라이브러리의 KNeighborsClassifier() 클래스를 사용한다. 해당 클래스의 공식 문서에서 안내하는 파라미터는 다음과 같다.

[n_neighbors]: 유형 - int, 기본값 - 5

  • 설명: 이웃의 수(예측에 사용되는 데이터 포인트의 수)
  • 입력값 범위: 1이상의 자연수

[weights]: 유형 - str or callable, 기본값 - ‘uniform’

  • 설명: 예측에 사용되는 데이터 포인트의 가중치
    ※ ‘uniform’: 모든 이웃의 가중치가 동일
    ※ ‘distance’: 가중치는 거리의 역수로 계산(IDW, Inverse Distance Weighting)
  • 입력값 범위: ‘uniform’, ‘distance’, callable, None

[algorithm]: 유형 - str, 기본값 - ‘auto’

  • 설명: 이웃을 계산하는데 사용되는 알고리즘
    ※ ‘auto’: ‘ball_tree’, ‘kd_tree’, ‘brute’ 중에서 가장 적합한 것을 자동으로 선택
    ※ ‘ball_tree’, ‘kd_tree’, ‘brute’: 각각의 알고리즘을 사용
  • 입력값 범위: ‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’

[leaf_size]: 유형 - int, 기본값 - 30

  • 설명: BallTree 또는 KDTree에 전달되는 값으로 잎사귀 노드(leaf node)에 할당될 수 있는 최대 데이터 포인트 크기
  • 입력값 범위: 1이상의 자연수

[p]: 유형 - int, 기본값 - 2

  • 설명: Minkowski metric의 파라미터
  • 입력값 범위: 1이상의 자연수

[metric]: 유형 - str, 기본값 - ‘minkowski’

  • 설명: 데이터포인트간 거리 계산에 사용되는 알고리즘
  • 입력값 범위: ‘minkowski’ 및 “scipy.spatial.distance”에서 제공되는 알고리즘
    scipy.spatial.distance 문서 페이지

[metric_params]: 유형 - dict, 기본값 - None

  • 설명: 거리 계산에 사용되는 알고리즘의 추가 인자
  • 입력값 범위: dict 또는 None

[n_jobs]: 유형 - int, 기본값 - None

  • 설명: 이웃 검색을 위해 병렬 작업을 실행하는데 사용되는 작업 수
  • 입력값 범위: None, -1, 1이상의 자연수

회귀 모델

수치형 종속변수를 예측하는 모델이며 종속변수가 연속적인 수치형 데이터인 경우에 사용한다.

k-NN 회귀모델을 구현하기 위해서는 sklearn 라이브러리의 KNeighborsRegressor() 클래스를 사용한다. 해당 클래스의 공식 문서에서 안내하는 파라미터는 KNeighborsClassifier() 클래스와 같다.

예제 코드

분류 모델

먼저 다음과 같이 라이브러리와 데이터를 준비하고 사용하는 데이터와 관련된 전처리 코드는 [Py) 전처리 - ML 분류모델용 - 01] 게시글을 참고하자.
model_classification_machine_failure.csv 다운받기 [클릭]

1
2
3
4
5
6
7
8
import pandas as pd

from sklearn.neighbors import KNeighborsClassifier # K-NN 분류모델
from sklearn.metrics import accuracy_score # 분류모델 평가(Accuracy)
from sklearn.metrics import f1_score # 분류모델 평가(F1 score)

df_machine = pd.read_csv("data/model_classification_machine_failure.csv")
df_machine.head(2)
id is_failure type_H type_L type_M temp_air temp_process speed torque tool_wear Xgrp
0 55100 0 0.0 1.0 0.0 0.399154 1.352290 -0.877336 0.926149 1.084815 train
1 49876 0 0.0 1.0 0.0 0.001026 -0.266219 -0.482743 0.596147 -0.889909 train

“Xgrp” 변수을 기준으로 학습과 평가 데이터세트로 나눈 후 학습에 불필요한 “id”, “Xgrp” 변수를 제거한다.

1
2
3
4
5
6
df_train = df_machine.loc[df_machine["Xgrp"] == "train", ]
df_test = df_machine.loc[df_machine["Xgrp"] == "test", ]
df_train = df_train.drop(columns = ["id", "Xgrp"]).reset_index(drop = True)
df_test = df_test.drop( columns = ["id", "Xgrp"]).reset_index(drop = True)

df_train.head(2)
is_failure type_H type_L type_M temp_air temp_process speed torque tool_wear
0 0 0.0 1.0 0.0 0.399154 1.352290 -0.877336 0.926149 1.084815
1 0 0.0 1.0 0.0 0.001026 -0.266219 -0.482743 0.596147 -0.889909

KNeighborsClassifier() 클래스를 사용하여 이웃의 수(n_neighbors)를 3으로 설정한 후 학습을 진행한다. 여기서 필요시 각 파라미터를 조정하여 학습을 진행할 수 있다.

1
2
3
4
5
6
model_c = KNeighborsClassifier(n_neighbors = 3)
model_c.fit(X = df_train.drop(columns = "is_failure"),
y = df_train["is_failure"])
pred = model_c.predict(df_test.drop(columns = "is_failure"))
pred[:4]
## array([0, 0, 0, 0], dtype=int64)

학습된 모델을 평가하기 위해 Accuracy와 F1-score를 계산해본다.

1
2
3
4
5
accuracy_score(y_true = df_test["is_failure"], y_pred = pred)
## 0.9789649415692822

f1_score(y_true = df_test["is_failure"], y_pred = pred)
## 0.5263157894736843

회귀 모델

먼저 다음과 같이 라이브러리와 데이터를 준비하고 사용하는 데이터와 관련된 전처리 코드는 [Py) 전처리 - ML 회귀모델용 - 01] 게시글을 참고하자.
model_regression_ins_charges.csv 다운받기 [클릭]

1
2
3
4
5
6
7
8
import pandas as pd

from sklearn.neighbors import KNeighborsClassifier # K-NN 분류모델
from sklearn.metrics import mean_squared_error # 회귀모델 평가(MSE, RMSE)
from sklearn.metrics import mean_absolute_percentage_error # 회귀모델 평가(MAPE)

df_ins = pd.read_csv("data/model_regression_ins_charges.csv")
df_ins.head(2)
id charges gender is_smoker age bmi children region_B region_C region_D Xgrp
0 10182 4796 0 0 0.326087 0.641916 0.2 0.0 0.0 0.0 train
1 11118 12949 1 0 0.826087 0.476190 0.8 0.0 0.0 0.0 train

“Xgrp” 변수을 기준으로 학습과 평가 데이터세트로 나눈 후 학습에 불필요한 “id”, “Xgrp” 변수를 제거한다.

1
2
3
4
5
6
df_train = df_ins.loc[df_ins["Xgrp"] == "train", ]
df_test = df_ins.loc[df_ins["Xgrp"] == "test", ]
df_train = df_train.drop(columns = ["id", "Xgrp"]).reset_index(drop = True)
df_test = df_test.drop( columns = ["id", "Xgrp"]).reset_index(drop = True)

df_train.head(2)
charges gender is_smoker age bmi children region_B region_C region_D
0 4796 0 0 0.326087 0.641916 0.2 0.0 0.0 0.0
1 12949 1 0 0.826087 0.476190 0.8 0.0 0.0 0.0

KNeighborsRegressor() 클래스를 사용하여 이웃의 수(n_neighbors)를 3으로 설정한 후 학습을 진행한다. 여기서 필요시 각 파라미터를 조정하여 학습을 진행할 수 있다.

1
2
3
4
5
6
model_r = KNeighborsRegressor(n_neighbors = 3) # 모델 생성
model_r.fit(X = df_train.drop(columns = "charges"), # 학습
y = df_train["charges"])
pred = model_r.predict(df_test.drop(columns = "charges")) # 예측
pred[:4]
## array([27149.66666667, 15990. , 7055.66666667, 11208. ])

학습된 모델을 평가하기 위해 RMSE와 MAPE를 계산해본다.

1
2
3
4
5
mean_squared_error(y_true = df_test["charges"], y_pred = pred) ** 0.5
## 6500.71026225844

mean_absolute_percentage_error(y_true = df_test["charges"], y_pred = pred)
## 0.42165083680354676
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×