#!/usr/bin/env python3

k_NN(k-최근접 이웃) Regression


k-NN 회귀모델을 알아보겠습니다.
k-NN regression의 동작환경은 다음과 같습니다.

import mglearn

import matplotlib.pyplot as plt

mglearn.plots.plot_knn_regression(n_neighbors=1)
plt.show()

n_neighbors=1 일때 algorithm

x축에 3개의 테스트 데이터를 녹색 별로 표시합니다.
최근접 이웃을 한 개만 사용할 때 예측은 가장 가까운 데이터 포인트의 값으로 인식합니다.

다음은 이웃의 수가 3일 때 knn algorithm의 동작 환경입니다.
mglearn.plots.plot_knn_regression(n_neighbors=3)
plt.show()

n_neighbors=3 일때 algorithm

마찬가지로 3개의 녹색 테스트 데이터를 기준으로 가장 이웃한 3개의 최근접 데이터 포인트를 구합니다.
그리고 나서 각 데이터포인트사이의 거리의 역수를 가중치로 타겟 값을 산정합니다.


이해를 돕기위해 인위적 데이터를 사용하여 k-NN Regression을 사용해보겠습니다.
from mglearn.datasets import make_wave
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsRegressor

x, y = make_wave(n_samples=40)

x_train, x_test, y_train, y_test = \
  train_test_split(x, y, 
                   random_state=0, test_size=0.3)

knn_reg = KNeighborsRegressor(n_neighbors=3, n_jobs=-1) n_jobs = 사용할 코어의 수, -1 => 모든 코어 사용
knn_reg.fit(x_train, y_train)

print('{:.3f}'.format(knn_reg.score(x_test, y_test)))
# 0.697


1차원 데이터 셋이므로 시각화가 가능하므로 n_neighbors의 값에 따라 어떻게 변하는지 확인해보겠습니다.
import numpy as np
_, axes = plt.subplots(1, 3)

line = np.linspace(-5, 5, num=1000)
line = line.reshape(-1, 1)

for i, ax in zip([1, 3, 9], axes.ravel()):
    knn_reg = KNeighborsRegressor(n_neighbors=i, n_jobs=-1)
    knn_reg.fit(x_train, y_train)

    prediction = knn_reg.predict(line)
    ax.plot(line, prediction, label='model predict', c='k'
    ax.scatter(x_train, y_train, marker='^', c='darkred', label='train target')
    ax.scatter(x_test, y_test, marker='v', c='darkblue', label='test target')
    
    train_score = knn_reg.score(x_train, y_train)
    test_score = knn_reg.score(x_test, y_test)
    ax.set_title('k={}\ntest score={:.3f}\ntrain score={:.3f}'.format(i, train_score, test_score))
    ax.set_xlabel('feature')
    ax.set_ylabel('target')
axes[0].legend(loc=2)
plt.show()

n_neighbors 값에 따라 최근접 이웃 회귀로 만들어진 예측 회귀 비교

이웃을 하나만 사용할 때는 훈련 세트의 각 데이터 포인트가 모든 선을 통과합니다. 이 것은 너무 복잡하게 모델이 짜여져 있는 것을 말하며 실제로 예측할 때는 그 결과가 좋지 못합니다. 반대로 이웃을 많이 사용할 수록 훈련 데이터에는 잘 안맞을 수 있지만 높은 정확도를 얻게 됩니다.


k-NN은 이해하기 매우 쉬운 모델입니다. 그러나 수백 개 이상의 많은 특성을 가진 데이터 셋에는 잘 동작하지 않으며 특성값이 0이 많은 데이터셋이는 잘 작동하지 않습니다.
또한 예측이 느리고, 많은 특성을 처리하는 능력이 부족하여 현업에서는 잘 쓰지 않습니다.
KNeighborsRegressor와 KNeighborsClassifier의 객체를 생성할 때 'metric' parameter를 사용하여 거리 측정 방식을 변경할 수 있습니다. 'metric' parameter의 기본값은 'minkowski', 거듭제곱의 크기를 정하는 parameter느 'p'입니다.
metric='minkowski', p=2는 metric='euclidean'과 같습니다.



참고 자료: 

[1]Introduction to Machine Learning with Python, Sarah Guido


'python 머신러닝 -- 지도학습 > Regression' 카테고리의 다른 글

Decision Tree Regressor  (0) 2018.03.14
Lasso  (0) 2018.03.13
Ridge  (0) 2018.03.12
LinearRegression  (0) 2018.03.12

#!/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

'python 머신러닝 -- 지도학습 > Classifier' 카테고리의 다른 글

Random Forest  (0) 2018.03.15
Decision Tree  (0) 2018.03.14
Multi Linear Classification  (0) 2018.03.14
Logistic Regression  (1) 2018.03.13
k_NN(k-최근접 이웃) Classifier[1]  (0) 2018.03.11
#!/usr/bin/env python3

k_NN(k-최근접 이웃)  Classifier[1]


분석을 위해 iris데이터를 로드합니다.

from sklearn.datasets import load_iris


iris = load_iris()



iris데이터의 형태는 다음의 코드로 확인할 수 있습니다.

print('''iris's key ==> {}'''.format(iris.keys()))

# iris's key ==> dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names'])


print('''iris's shape ==> {}'''.format(iris.data.shape))

# iris's shape ==> (150, 4)


print('''iris's data의 처음 6행 ==> \n{}'''.format(iris.data[:6]))

# iris's data의 처음 6행 ==> 

# [[5.1 3.5 1.4 0.2]

#  [4.9 3.  1.4 0.2]

#  [4.7 3.2 1.3 0.2]

#  [4.6 3.1 1.5 0.2]

#  [5.  3.6 1.4 0.2]

#  [5.4 3.9 1.7 0.4]]


print('''iris's feature names ==> \n{}'''.format(iris.feature_names))

# iris's feature names ==> 

# ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']



머신러닝 데이터학습을 위해 데이터를 분할합니다. 이 방법은 앞으로도 계속 사용합니다.

from sklearn.model_selection import train_test_split


x_train, x_test, y_train, y_test = \

  train_test_split(iris.data, iris.target,

                   test_size=0.3, random_state=0)



이제 데이터를 분할했으니 머신러닝을 사용할 때입니다.

이번 포스팅에서는 가장 기본적인 KNN 최근접이웃 머신러닝을 사용합니다.

머신러닝 algorithm을 사용하기 위해서는 학습시킬 데이터를 fitting해야합니다.

from sklearn.neighbors import KNeighborsClassifier


# n_neighbors는 가장 가까운 이웃을 몇개를 고를지에 대한 parameter며

# n_jobs는 사용할 코어의 갯수 입니다. -1이면 모든 코어를 사용합니다.

knn = KNeighborsClassifier(n_neighbors=1, n_jobs=-1)

knn.fit(x_train, y_train)



sample data를 만들어 확인해보겠습니다.

import numpy as np


# ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']

x_sample = np.array([[5, 2.9, 1, 0.2]])

prediction = knn.predict(x_sample)

results = {p:n for p, n in zip(prediction, iris.target_names[prediction])}

print('sample test ==> {}'.format(results))

# sample test ==> {0: 'setosa'}

knn(n_neighbors=1)를 이용하여 sample test 예측했을 때는 'setosa'라고 결과를 냈습니다.



이제 위에서 분할한 test data로 예측하면

prediction = knn.predict(x_test)

results = [iris.target_names[p] for p in prediction]

print('results의 처음 6개 ==> {}'.format(results[:6]))

# results의 처음 6개 ==> ['virginica', 'versicolor', 'setosa', 'virginica', 'setosa', 'virginica']


bins = np.bincount(prediction)

count = {n:c for n, c in zip(iris.target_names, bins)}

print('test 결과의 빈도수 ==> {}'.format(count))

# test 결과의 빈도수 ==> {'setosa': 16, 'versicolor': 17, 'virginica': 12}



정확도는 2가지 방법으로 구할 수 있습니다.

KNeighborsClassifier의 score메소드를 이용하거나 직접 계산하는 방법입니다.

print('score 메소드 이용 ==> {:.3f}'.format(knn.score(x_test, y_test)))

# score 메소드 이용 ==> 0.978


y_pred = knn.predict(x_test)

print('numpy 이용 ==> {:.3f}'.format(np.mean(y_pred == y_test)))

# numpy 이용 ==> 0.978



훈련 데이터를 시각화 해보겠습니다.

pandas를 이용할 것이기 때문에 훈련 데이터를 DataFrame으로 변환하고

열이름은 featre_names를 사용하겠습니다.

import pandas as pd

import matplotlib.pyplot as plt

import matplotlib


matplotlib.rc('font', family='AppleGothic') # 한글출력

plt.rcParams['axes.unicode_minus'] = False # 축 - 표시


iris_df = pd.DataFrame(x_train, columns=iris.feature_names)

pd.scatter_matrix(iris_df,

                  c=y_train, # 색깔로 구분할 데이터

                  hist_kwds={'bins':30}, # 히스토그램

                  marker='o', # marker

                  s=20, # size

                  alpha=0.5) # 투명도

plt.show()


pandas를 이용한 scatter_matrix

이 그래프를 통해 훈련데이터의 개괄적인 정보를 한번에 파악할 수 있습니다.




참고 자료: 

[1]Introduction to Machine Learning with Python, Sarah Guido


'python 머신러닝 -- 지도학습 > Classifier' 카테고리의 다른 글

Random Forest  (0) 2018.03.15
Decision Tree  (0) 2018.03.14
Multi Linear Classification  (0) 2018.03.14
Logistic Regression  (1) 2018.03.13
k_NN(k-최근접 이웃) Classifier[2]  (1) 2018.03.12

+ Recent posts