< [핸즈온 머신러닝 2판] 3장 연습문제 1번

프로그래밍 공부/핸즈온 머신러닝 2판

[핸즈온 머신러닝 2판] 3장 연습문제 1번

Rocketbabydolls 2022. 10. 29. 20:52

[1번] MNIST 데이터셋으로 분류기를 만들어 테스트 세트에서 97%의 정확도를 달성해보세요. 

(힌트 : KNeighborsClassifier 가 이 작업에 아주 잘 맞습니다. 좋은 하이퍼파라미터 값만 찾으면 됩니다. (wieghts와 n_neighbors 하이퍼파라미터로 그리드 탐색을 시도해보세요).)

 

#사용할 데이터셋과 모델 임포트
from sklearn.datasets import fetch_openml
from sklearn.model_selection import GridSearchCV
from sklearn.neighbors import KNeighborsClassifier

#넘파이 임포트
import numpy as np

mnist = fetch_openml('mnist_784', version=1, as_frame=False) # as_frame = True 넘파이로 반환
mnist.keys()

  fetch_openml 메서드를 이용해 mnist_784 데이터프레임을 넘파이로 변환해 가져온다.

mnist.keys() 를 호출하면 출력값으로

  dict_keys(['data', 'target', 'frame', 'categories', 'feature_names', 'target_names', 'DESCR', 'details', 'url'])

가 나오는데, 이 중에 'data', 'target' 만 사용했다.

#데이터와 타겟 레이블을 추출
X, y = mnist["data"], mnist["target"]
#데이터 형태 확인
X.shape

  X, y  에 데이터와 타겟 레이블들을 지정 해주고, 데이터의 형태를 확인했다. X.shape 를 호출하면 자동으로 데이터의 쉐입을 출력해 주는데 (70000, 784) 로 이미지가 70000개 있고, 특성이 784개가 있다는 뜻이다. 이때 특성이란 이미지의 가각 한 픽셀을 말한다. 28 * 28 픽셀로 이루어진 이미지이기 때문에, 각 픽셀의 밝기(흑백이기 떄문에 밝기이다.) 가 특성이 된다.

 

# target 레이블 은 문자열이기 때문에 정수로 변환
y = y.astype(np.uint8) 
# 59999번 인덱스를 기준으로 훈련 세트와 테스트 세트를 나눔
X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:]

 그리고 y[0] 호출을 통해 타깃 레이블의 첫 번째 원소를 살펴보면 '5' 로 나오기 때문에 문자열을 astype 메서드를 사용해 정수로 변환해준다. 변환 후 70000개의 이미지 중 60000개를 훈련 세트, 10000개를 테스트 세트로 나눈다.  훈련 세트로 모델을 학습한 뒤 정확도 97%를 얻는 것이 우리의 목표이다.

 

 

#weigths 에서 uniform : 가중치마다 같은 값을 부여, distance : 거리가 더 가까운 이웃의 영향을 더 많이 받도록 가중치 설정
param_grid = [{'weights': ["uniform", "distance"], 'n_neighbors': [3, 4, 5]}]

knn_clf = KNeighborsClassifier() 
grid_search = GridSearchCV(knn_clf, param_grid, cv=5, verbose=3)
grid_search.fit(X_train, y_train)

 

  문제에서 힌트를 준 것을 기억하고 그리드 서치를 이용해 최적의 파라미터 값을 찾아야 한다.  weights 는 uniform 과 distance 두 개를 원소로 하는 배열을 넣어준다. 

  이때 uniform과 distance가 뜻하는 것이 궁금해 공식 문서를 찾아보았다.

 

weights{‘uniform’, ‘distance’} or callable, default=’uniform’

Weight function used in prediction. Possible values:

  • ‘uniform’ : uniform weights. All points in each neighborhood are weighted equally.
  • ‘distance’ : weight points by the inverse of their distance. in this case, closer neighbors of a query point will have a greater influence than neighbors which are further away.

 

출처 : https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html?highlight=kneighbors+uniform

 

sklearn.neighbors.KNeighborsClassifier

Examples using sklearn.neighbors.KNeighborsClassifier: Release Highlights for scikit-learn 0.24 Release Highlights for scikit-learn 0.24 Classifier comparison Classifier comparison Plot the decisio...

scikit-learn.org

 

  uniform 은 가까이 있는 포인트에 같은 가중치를 적용하는 것이고, distance는 거리가 좁을수록 많은 가중치를 부여하는 방식이다. 따라서 가까이 있는 포인트의 영향을 더 받게 된다. 

  n_neighbors 는 3,4,5 값을 넣어주어 주변의 몇개의 이웃까지 고려할 것인지를 정해준다. 

 

파라미터 설정은 끝났으니 그리드 서치 메서드에 전달해주어  fit 해주면 최적의 파라미터 값을 찾아준다.

 

#최적의 파라미터 값 확인
grid_search.best_params_

#테스트 세트에서의 최고 성적은 대략 97% 의 정확도.
grid_search.best_score_

 

  각각의 호출은 두 값을 출력한다.

best_params_  :  {'n_neighbors': 4, 'weights': 'distance'}

best_score_ : 0.9716166666666666

 

그리드서치로 최적의 파라미터는 distance 와 4개의 이웃을 살펴보는 것임을 찾아냈고, 최고 성능은  약 97%의 점수가 나왔다.

 

from sklearn.metrics import accuracy_score

#테스트 세트로 훈련이 아닌 예측을 하자.
y_pred = grid_search.predict(X_test)
accuracy_score(y_test, y_pred)

 

마지막으로 테스트 세트(아까 뗴어놓았던 10000개의 이미지 샘플) 에서 예측을 해보면  0.9714의 값이 나오는 것을 확인할 수 있다.  따라서 테스트 세트에서 97% 의 정확도를 달성하려는 목표에 도달했다.

 

전체 코드는 아래를 가면 볼 수 있다.

https://github.com/chataeg/handson-ML/blob/master/jupyter/examples/Hands_On_ch03_1.ipynb

 

GitHub - chataeg/handson-ML

Contribute to chataeg/handson-ML development by creating an account on GitHub.

github.com