카테고리 없음
test jupyter notebook
Assignment 1¶
- KNN으로 HyperParameter 이해하기¶
Load Dataset¶
Import packages¶
In [1]:
# data
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings("ignore")
# visualization
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
from pandas.plotting import parallel_coordinates
# preprocessing
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
# model
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
# grid search
from sklearn.model_selection import GridSearchCV
# evaluation
from sklearn.model_selection import cross_val_score
from sklearn.metrics import *
Load iris data¶
In [2]:
from sklearn.datasets import load_iris
# sklearn에 내장되어있는 iris 데이터를 사용
In [3]:
iris = load_iris()
In [4]:
print(iris.DESCR)
# iris dataset 정보를 알 수 있다
- feature에는 sepal length, sepal width, petal length, petal width가 있다.
- target은 3개의 class가 있으며 각각 Iris-Setosa, Iris-Versicolour, Iris-Virginica, 즉, 붖꽃의 종류이다.
- Setosa, Versicolour, Virginica가 각각 0, 1, 2로 분류 되어있다.
- 총 150개의 instance가 존재한다.
Make DataFrame¶
In [5]:
# feature와 target를 하나의 DataFrame으로 만들고 각각의 column명을 붙여주었다.
df = pd.DataFrame(iris.data, columns = iris.feature_names)
y = pd.Series(iris.target, dtype="category")
y = y.cat.rename_categories(iris.target_names)
df['species'] = y
In [6]:
df.head()
Out[6]:
EDA¶
In [7]:
df.describe()
Out[7]:
In [8]:
df.groupby('species').size()
Out[8]:
- 각 Class 별로 data가 50개씩 존재한다.
Pairplot¶
In [9]:
sns.pairplot(df, hue="species")
plt.show()
- petal length 만으로 0과 1종을 완전히 구분할 수 있다
- petal length와 petal width 두가지로 나누면 1과 2종도 구분해 낼 수 있을 것으로 보인다
Distplot¶
In [10]:
sns.distplot(df[df.species != "setosa"]["petal length (cm)"], hist=True, rug=True, label="setosa")
sns.distplot(df[df.species == "setosa"]["petal length (cm)"], hist=True, rug=True, label="others")
plt.legend()
plt.show()
- 위의 분포를 보면 petal length 하나의 변수만으로 setosa와 다른 종들을 쉽게 분류해낼 수 있을 것으로 보인다.
In [11]:
sns.distplot(df[df.species == "virginica"]["petal length (cm)"], hist=True, rug=True, label="virginica")
sns.distplot(df[df.species == "versicolor"]["petal length (cm)"], hist=True, rug=True, label="versicolor")
plt.legend()
plt.show()
- 반면 virginica와 versicolor는 petal length 만으로는 완전히 분류해내기 어려워보인다.
Parallel coordinates plot¶
In [12]:
parallel_coordinates(df, "species")
plt.xlabel('Features', fontsize=15)
plt.ylabel('Features values', fontsize=15)
plt.legend(loc=1, prop={'size': 15}, frameon=True, shadow=True, facecolor="white", edgecolor="black")
plt.show()
- 각 feature들로 얼마나 붓꽃 종류를 구분할 수 있는지 한눈에 알 수 있다.
- 앞에서 언급했듯이 petal length와 petal width로 0과 1를 구분해낼 수 있다
Boxplot¶
In [13]:
df.boxplot()
plt.show()
- 각 데이터의 분포를 살펴보았다.
- sepal_width 데이터에서 outlier가 있는 것을 알 수 있었다.
Preprocessing¶
- KNN을 사용하기에 앞서 거리를 구하는 것이 분류의 핵심이므로 Scaling을 해주기로 하였다.
- 그 전에 train data와 test data를 나누어 주기로 하였다.
Split data¶
In [14]:
# train과 test data를 0.75 : 0.25 비율로 나눈다.
X_train, X_test, y_train, y_test = train_test_split(df.iloc[:,:-1], df.iloc[:,-1], random_state=3)
Scaling¶
In [15]:
# Standard Scaler
ss = StandardScaler() # Scaling
X_train_s = pd.DataFrame(ss.fit_transform(X_train), columns = X_train.columns)
X_test_s = pd.DataFrame(ss.transform(X_test), columns = X_test.columns)
X_train_s.head()
Out[15]:
In [16]:
# Minmax Scaler
ms = MinMaxScaler()
X_train_m = pd.DataFrame(ms.fit_transform(X_train), columns = X_train.columns)
X_test_m = pd.DataFrame(ms.transform(X_test), columns = X_test.columns)
X_train_m.head()
Out[16]:
Modeling¶
Print metrics function¶
In [17]:
def print_metrics(model, X_train):
scores = cross_val_score(model, X_train, y_train, cv=10)
print('*** Cross val score *** \n {}'.format(scores))
print('\n*** Mean Accuracy *** \n {:.7f}'.format(scores.mean()))
# print('\n*** Confusion Matrix *** \n', confusion_matrix(y_train, model.predict(X_train)))
- 한번에 validation용 metrics를 출력할 수 있는 함수를 생성하였다.
Simple Model¶
In [18]:
knn = KNeighborsClassifier()
knn.fit(X_train, y_train)
print_metrics(knn, X_train)
Standard Scaled Model¶
In [19]:
knn_s = KNeighborsClassifier()
knn_s.fit(X_train_s, y_train)
print_metrics(knn_s, X_train_s)
MinMax Scaled Model¶
In [20]:
knn_m = KNeighborsClassifier()
knn_m.fit(X_train_m, y_train)
print_metrics(knn_m, X_train_m)
Hyperparameter Tuning¶
Parameters¶
- n_neighbors: 검색할 이웃의 수로 default 값은 5이다.
- Metric: 거리 측정 방식을 변경하는 매개변수로 default 값은 minkowsi이다
- Weights: 예측에 사용하는 가중치로 uniform 은 각 이웃에 동일한 가중치를 , ‘distance’는 가까운 이웃이 멀리 있는 이웃보다 더욱 큰 영향을 미친다.
Grid Search CV¶
In [21]:
grid_params = {
'n_neighbors' : list(range(1,20)),
'weights' : ["uniform", "distance"],
'metric' : ['euclidean', 'manhattan', 'minkowski']
}
1. No Scaled¶
In [22]:
gs = GridSearchCV(knn, grid_params, cv=10)
gs.fit(X_train, y_train)
print("Best Parameters : ", gs.best_params_)
print("Best Score : ", gs.best_score_)
print("Best Test Score : ", gs.score(X_test, y_test))
2. Standard Scaled¶
In [23]:
gs_s = GridSearchCV(knn_s, grid_params, cv=10)
gs_s.fit(X_train_s, y_train)
print("Best Parameters : ", gs_s.best_params_)
print("Best Score : ", gs_s.best_score_)
print("Best Test Score : ", gs_s.score(X_test_s, y_test))
3. MinMax Scaled¶
In [24]:
gs_m = GridSearchCV(knn_m, grid_params, cv=10)
gs_m.fit(X_train_m, y_train)
print("Best Parameters : ", gs_m.best_params_)
print("Best Score : ", gs_m.best_score_)
print("Best Test Score : ", gs_m.score(X_test_m, y_test))
- Score의 결과가 가장 좋은 MinMax Scaled Data의 {'metric': 'euclidean', 'n_neighbors': 9, 'weights': 'uniform'} parameters를 선택하기로 하였다.
Final Model¶
In [25]:
knn_m = KNeighborsClassifier(metric = 'euclidean', n_neighbors = 9, weights = 'uniform')
knn_m.fit(X_train_m, y_train)
print_metrics(knn_m, X_train_m)
Evaluation¶
In [26]:
def print_test_metrics(model, X_test):
print('*** Test Accuracy *** \n {}'.format(model.score(X_test, y_test)))
print('\n*** Confusion Matrix *** \n', confusion_matrix(y_test, model.predict(X_test)))
In [27]:
print_test_metrics(knn_m, X_test_m)
- 하나의 test instance를 제외하고 모두 분류해냈다.
- 역시 setosa는 완전히 분류해냈으나 나머지 두 종을 분류해내기 힘들었던 것 같다.
댓글