#!/usr/bin/env python3
k_NN(k-최근접 이웃) Classifier[2]
k-NN algorithm은 가장 가까운 데이터 포인트중 n_neighbors만큼 이웃으로 삼아 예측으로 사용합니다.
다음은 k-NN algorithm을 보여줍니다.
import matplotlib.pyplot as plt
import mglearn
mglearn.plots.plot_knn_classification(n_neighbors=1)
plt.xlabel('feature 0')
plt.ylabel('feature 1')
plt.title('n_neighbors=1')
plt.legend(feature_list, loc=(1.01, 0.4))
plt.show()
n_neighbors=1 일 때 algorithm
mglearn.plots.plot_knn_classification(n_neighbors=3)
plt.xlabel('feature 0')
plt.ylabel('feature 1')
plt.title('n_neighbors=3')
plt.legend(feature_list, loc=(1.01, 0.4))
plt.show()
n_neighbors=1 일 때 algorithm
이번에는 n_neighbors의 숫자에 따른 결정 경계를 그려보겠습니다.
먼저 임의로 데이터셋을 만들어보겠습니다.
from mglearn.datasets import make_forge
x, y = make_forge()
_, axes = plt.subplots(1, 3)
for i, ax in zip([1, 3, 9], axes.ravel()):
knn = KNeighborsClassifier(i)
knn.fit(x, y)
mglearn.plots.plot_2d_separator(knn, x, fill=True,
eps=0.5, alpha=0.5, ax=ax)
mglearn.discrete_scatter(x[:, 0], x[:, 1],
y=y, ax=ax)
ax.set_title('k={}'.format(i))
ax.set_xlabel('feature 0')
ax.set_ylabel('feature 1')
axes[0].legend(loc=(0.01, 1.01))
plt.show()
n_neighbors 값에 따른 k-NN모델이 만든 decision boundary
이 그림을 보면 제일 왼쪽인 k=1일 경우에 모든 데이터를 가장 정확하게 분류했으며 그 경계는 복잡합니다.
k의 값이 커질수록 경계선은 점점 수평에 가까워지며 경계는 완만해짐을 알 수 있습니다.
실제wine 데이터를 분석해보겠습니다.
분석하기전에 wine데이터의 전체적인 구조를 pandas의 scatter_matrix를 이용해서
확인해보겠습니다. 이 작업은 데이터틔 outlier가 있는지 쉽게 확인할 수 있는 장점이 있습니다.
from sklearn.datasets import load_wine
import pandas as pd
wine = load_wine()
print(wine.keys())
# dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names'])
for i in range(len(wine.feature_names)):
print('{}:{}'.format(i, wine.feature_names[i]))
# 0:alcohol
# 1:malic_acid
# 2:ash
# 3:alcalinity_of_ash
# 4:magnesium
# 5:total_phenols
# 6:flavanoids
# 7:nonflavanoid_phenols
# 8:proanthocyanins
# 9:color_intensity
# 10:hue
# 11:od280/od315_of_diluted_wines
# 12:proline
wine_df = pd.DataFrame(wine.data, columns=range(len(wine.feature_names)))
pd.scatter_matrix(wine_df, # dataframe
c=wine.target, # color
hist_kwds={'bins':30}, # hist kwords
s=10, # size
alpha=0.5, # alpha
marker='o') # marker
plt.show()
wine의 scatter_plot
그래프가 복잡해 보일지 모르겠지만 전체적인 구조를 한 눈에 파악할 수 있습니다.
데이터를 파악했으니 k-NN 최근접 이웃 algorithm, n_neighbors=3으로 데이터를 분석해보겠습니다.
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test =\
train_test_split(wine.data, wine.target, stratify=wine.target, # stratify = 계층화
random_state=0, test_size=0.3)
knn = KNeighborsClassifier(n_neighbors=3, n_jobs=-1) # jobs = 사용할 코어의 수, -1 => 모든 코어
knn.fit(x_train, y_train)
print('{:.3f}'.format(knn.score(x_test, y_test)))
# 0.648
약 KNeighborsClassifier(n_neighbors=3)으로 와인의 품종을 테스트한 결과 약 70%의 정확도를 나타내는 것을
볼 수 있습니다.
이번엔 이 데이터로 모델의 복잡도와 일반화사이의 관계를 알아보겠습니다.
위의 임의로 만든 데이터로 알아본 결과 모델의 복잡도를 알아보았는데 실제 데이터셋으로 모델의 복잡도와 정확도를 알아보겠습니다.
from sklearn.datasets import load_wine
import matplotlib.pyplot as plt
wine = load_wine()
x_train, x_test, y_train, y_test = \
train_test_split(wine.data, wine.target, stratify=wine.target,
test_size=0.3, random_state=0)
train_list = []
test_list = []
n_range = range(1, 20)
for i in n_range:
knn = KNeighborsClassifier(n_neighbors=i, n_jobs=-1)
knn.fit(x_train, y_train)
tr_score = knn.score(x_train, y_train)
te_score = knn.score(x_test, y_test)
train_list.append(tr_score)
test_list.append(te_score)
plt.plot(n_range, train_list, color='red', ls='--', lw=2, label='train accuracy') # ls = linestyle, lw= linewidth
plt.plot(n_range, test_list, color='green', lw=2, label='test accuracy')
plt.xticks(n_range)
plt.xlabel('n_neighbors')
plt.ylabel('accuracy')
plt.legend()
plt.show()
n_neighbors 변화에 따른 훈련 정확도와 테스트 정확도
이웃의 수(n_neighbors)가 작을수록 모델이 복잡해지고 모델의 정확도는 100%입니다.
그러나 예측 정확도는 0.7정도인 것을 알수있으며
이웃의 수를 증가시켜도 예측 정확도는 많이 늘어나지는 않습니다.
따라서 이 데이터에는 k-NN 최근접 algorithm이 적합하지 않음을 알 수 있습니다.
참고 자료:
[1]Introduction to Machine Learning with Python, Sarah Guido