[핸즈온 머신러닝 2판] 3장 분류(MNIST 데이터)

2021. 11. 18. 19:40나혼머(나혼자머신러닝)/핸즈온머신러닝2판

2021.11.18.목

 

 

1. 데이터 : MNIST 

 : 고등학생 & 미국인구조사국 직원이 손으로 쓴 70,000개의 작은 숫자 이미지 데이터를 모은 MNIST 데이터 셋

 

2. 데이터 설명 : 

 - 각 이미지에 어떤 숫자를 나타내는지 레이블이 되어 있음. 학습용으로 가장 많이 사용됨.

 - 새로운 분류 알고리즘이 나올 때마다 MNIST 데이터셋에서 얼마나 잘 작동하는지 확인함

 

3. 실습

 

 3-1. 필요한 라이브러리 import 

from sklearn.datasets import fetch_openml

 -> sklearn의 datasets에서 제공하는 fetch_openml 라이브러리 임포트(import)

 

 3-2. Mnist 데이터 load

mnist = fetch_openml('mnist_784', version=1)
mnist

 -> 사이킷런에서 읽어 들인 데이터셋은 일반적으로 비슷한 딕셔너리 구조를 가지고 있다고 함

mnist 의 target : 레이블 배열을 담은 정답 데이터 

mnist 의 data : 하나의 행, 특성이 하나의 열로 구성된 배열을 가진 데이터

 

3-3. X, y 변수에 mnist의 data 특성, mnist의 target 특성 넣기

X,y = mnist['data'], mnist['target']
print(X.shape)
print(y.shape)

>>> (70000, 784)
>>> (70000,)

 

-> 이미지가 70,000개 있고 각 이미지는 784개의 속성이 있음 ( 이미지가 28X28 픽셀 이므로)

-> 개개의 특성은 단순히 0(흰색)에서 255(검은색) 까지의 픽셀 강도를 나타냄

 

3-4. 데이터 셋에서 이미지 하나를 확인해보기.

 샘플의 특성 벡터를 추출하여 28X28 배열로 크기를 바꾸고 matplotlib의 imshow() 함수 사용

import matplotlib as mpl
import matplotlib.pyplot as plt

* 책에는 some_digit 변수에 X[0] 을 넣도록 되어 있는데, 그럼 Keyerror 나는데용?

 

그래서 그냥 첫번째꺼 시리즈로 불러와서 np 행렬로 만든다음에 28x28로 리사이징해주고, imshow 함수로 나타냄

some_digit = X.loc[0].values
some_digit_image = some_digit.reshape(28,28)

plt.imshow(some_digit_image, cmap='binary')
plt.axis('off')
plt.show()

 실제레이블은요 ?

3-5.  현재 레이블은 문자열임, 그러나 머신러닝 알고리즘은 숫자를 기대하므로 y를 정수로 변환함! 

import numpy as np

y = y.astype(np.uint8)
y

 

3-6. MNIST 데이터셋을 훈련 세트, 테스트 세트로 나눔 (앞 60000개, 뒤 10000개)

X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:]

>>> (60000, 784) (10000, 784) (60000,) (10000,)

 

3-7. 이진분류기 훈련 (binary classifier)

 5-감지기 -> 5임/ 5아님 으로 분류하는 분류기를 만들자 ! 

y_train_5 = (y_train == 5)
y_test_5 = (y_test == 5)

 

3-8. 사이킷런의 SGDClassifier 클래스 사용 SGD 분류기 사용(확률적 경사하강법 분류기)

 -> 매우 큰 데이터셋을 효율적으로 처리하는 장점.

 -> 한 번에 하나씩 훈련 샘플을 독립적으로 처리해서 온라인 학습에 잘 맞음

 

from sklearn.linear_model import SGDClassifier
sgd_clf = SGDClassifier(random_state=42)
sgd_clf.fit(X_train, y_train_5)
sgd_clf.predict([some_digit])

>>> array([ True])

 

 3-9. 해당 모델의 성능 측정 !

 

   3-9-(1) 성능 측정 방법 : 오차행렬(Counfusion Matrixs)

 

-> 오차행렬을 만들기 위해서는 실제 타깃과 비교할 수 있도록 먼저 예측값을 만들어야함.

-> cross_val_predict() 함수는 k-겹 교차 검증을 수행하지만 평가 점수를 반환하지 않고,

    각 테스트 폴드에서 얻은 예측을 반환함. 

 

step1. 오차행렬(Counfusion Matrixs) 성능 측정 

from sklearn.model_selection import cross_val_predict

-> cross_val_predict()함수를 사용하여 예측값을 만들어줌 

 

step 2. Target 클래스인 y_train_5와 예측 클래스 y_train_pred를 넣고 호출

y_train_pred = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3)

step 3. 오차행렬 생성

from sklearn.metrics import confusion_matrix

step 4. 오차행렬의 행은 실제 클래스, 열은 예측한 클래스를 나타냄

confusion_matrix(y_train_5, y_train_pred)
array([[53892,   687],
       [ 1891,  3530]], dtype=int64)

 -> 첫번째 행은 음성 클래스(Negative class)에 관한 것. '5'가 아닌 이미지 

 고로 53892는 '5 아님'으로 예측하고 진짜 '5아님' : 진짜 음성 TN

        687은 '5임' 으로 예측했지만 진짜는 '5 아님' : FP

      1891은 '5아님' 으로 예측했지만 진짜는 '5임' : FN
       3530은 '5 임' 으로 예측하고 진짜 '5임' : TP

 

  * 오차행렬은 볼때마다 햇갈려서 다시 공부해야함 짲증나!!!!!!!!! * 

 

 step 5. 오차행렬에서의  정밀도(Precision)와 재현율(Recall)  

# 정밀도와 재현율

from sklearn.metrics import precision_score, recall_score
precision_score(y_train_5, y_train_pred)


>>> 0.8370879772350012

 step 6. 오차행렬에서의 f1 score

from sklearn.metrics import f1_score

f1_score(y_train_5, y_train_pred)

>>> 0.7325171197343846

 

오차행렬을 하면서 정밀도/재현율/f1 스코어 갔다가 트레이드 오프 그래프 찍다가 혼미해짐

내일 계속 _ ★