K-Nearest Neighbor로 대표적인 지도학습 알고리즘이다. 새로운 데이터가 들어왔을 때 기존 데이터의 그룹 중 어떤 그룹에 속하는지 분류하는 문제를 말한다. 자주 사용되지는 않지만 가끔 성능이 괜찮은 경우가 있다.
이 글을 쓰게된 이유도 지금 하고 있는 경진대회에서 KNN이 성능이 최고는 아니지만 준수한 성능을 보여서 다른 모델과 ensemble을 시도해보려고 하고 그런 김에 내용을 정리해 두면 좋을 것 같아서 쓰게 되었다.
우선 uniform 방식으로 원리를 설명하자면 다음과 같다.
만약에 탐색할 이웃 수를 3로 설정한다면, 새로 들어온 별과 가장 가까운 이웃 3개는 네모 2개, 동그래미 1개이기 때문에 별의 그룹은 네모로 결정된다.
sklearn의 KNeighborsClassifier 기준으로 알아보자
주요 파라미터는 2가지이다.
- n_neighbors : int, default=5, 이웃 수를 지정
- weights : 'uniform', 'distance', (custum 방식도 있는데 이는 생략) 2가지 중에서 uniform은 위에서 설명한 방식이고 distance의 경우는 가까운 거리의 이웃에 가중치를 두는 방식이다. 그러니까 uniform의 경우 거리에 따른 가중치가 동일하다는 뜻이다.
sklearn의 iris 데이터를 가지고 실습해보자
from sklearn.datasets import load_iris
iris = load_iris(as_frame=True)
iris.keys()
>>> dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename', 'data_module'])
as_frame=True로 지정하면 frame이라는 키가 생기고 iris.frame으로 판다스 데이터프레임 형태로 데이터를 얻을 수 있다.
from sklearn.model_selection import train_test_split
X = iris.data[["sepal length (cm)", "sepal width (cm)"]]
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0)
2차원 시각화를 하기 위해서 feature 2개만 사용한다.
from sklearn.neighbors import KNeighborsClassifier
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
clf = Pipeline(
steps=[("scaler", StandardScaler()), ("knn", KNeighborsClassifier(n_neighbors=11))]
)
스케일러와 모델을 포함한 파이프라인을 정의해주고 이웃 수는 11로 설정해주었다.
import matplotlib.pyplot as plt
from sklearn.inspection import DecisionBoundaryDisplay
_, axs = plt.subplots(ncols=2, figsize=(12, 5))
for ax, weights in zip(axs, ("uniform", "distance")):
clf.set_params(knn__weights=weights).fit(X_train, y_train)
disp = DecisionBoundaryDisplay.from_estimator(
clf,
X_test,
response_method="predict",
plot_method="pcolormesh",
xlabel=iris.feature_names[0],
ylabel=iris.feature_names[1],
shading="auto",
alpha=0.5,
ax=ax,
)
scatter = disp.ax_.scatter(X.iloc[:, 0], X.iloc[:, 1], c=y, edgecolors="k")
disp.ax_.legend(
scatter.legend_elements()[0],
iris.target_names,
loc="lower left",
title="Classes",
)
_ = disp.ax_.set_title(
f"3-Class classification\n(k={clf[-1].n_neighbors}, weights={weights!r})"
)
plt.show()
한 (6.8, 2.8) 정도를 보면 2가지 방식에 따라 경계선이 달라졌음을 알 수 있다. uniform의 경우 해당 위치의 초록색이 노랑색 경계에 포함되어 있지만 distance의 경우 가장 가까이에 있는 초록색 이웃의 영향을 받아 초록색으로 분류되었다.
즉 데이터에 따라 k값이나, distance 방식을 하이퍼파라미터 튜닝하여 적절한 것을 찾아야 한다.
'Machine Learning > 코드 실습' 카테고리의 다른 글
Decision Tree 실습 (0) | 2023.12.04 |
---|