1. mnist 데이터 불러오기
from sklearn.datasets import fetch_openml
import numpy as np
mnist = fetch_openml('mnist_784', version=1)
mnist.keys()
- mnist 데이터는 dictionary 구조로 이루어져있다.
- DESCR : 데이터셋 설명
- data : 샘플이 하나의 행, 특성이 하나의 열
- target : 레이블 배열
X, y = mnist["data"], mnist["target"]
X.shape
y.shape
- 70,000 개의 이미지
- 각 이미지에는 784개의 특성 (28 * 28 = 784 픽셀)
- 각 픽셀은 0 ~ 255까지의 픽셀 강도를 나타냄
import matplotlib as mpl
import matplotlib.pyplot as plt
#첫 번째 데이터는 숫자 5임
some_digit = X[0]
some_digit_image = some_digit.reshape(28,28)
plt.imshow(some_digit_image, cmap="binary")
plt.axis("off")
plt.show()
#numpy.uint8 object type
y[0]
문자열 --> 숫자로 변경 (대부분의 알고리즘은 숫자를 기대하므로)
y = y.astype(np.uint8)
테스트와 훈련 데이터로 분리한다. (70,000개이므로 훈련 6 : 테스트 1 정도로 분리한다)
X_train, X_test, Y_train, Y_test = X[:60000], X[60000:], y[:60000], y[60000:]
- mnist 데이터는 이미 섞여있어서 모든 교차 검증 폴드를 비슷하게 만든다.
- 만약 섞이지 않은 데이터를 사용한다면 꼭 섞어야함. 어떤 알고리즘은 훈련 샘플의 순서에 매우 민감하기때문에 동일한 샘플이 연달아서 나오게 된다면 성능이 저하될 수 있다.
2. 이진 분류기 훈련
간단히 숫자 5만 식별하는 이진 분류기 생성을 위한 타깃 벡터 생성 (5)
#5는 True, 나머지는 False
y_train_5 = (y_train == 5)
y_test_5 = (y_test == 5)
SGD (확률적 경사 하강법) 분류기 (매우 큰 데이터셋 효율적으로 처리 + 온라인 학습에 적절)
from sklearn.linear_model import SGDClassifier
sgd_clf = SGDClassifier(random_state = 42)
sgd_clf.fit(X_train, y_train_5)
- SGDClassifier 는 훈련하는 데 무작위성을 사용 (확률적)
- 결과 재현을 위해 random_state 난수 적용
#some_digit는 X[0] = 5 임
sgd_clf.predict([some_digit])
5라고 정확하게 예측함
3. 성능 측정
3.1 교차 검증
- cross_val_score() 함수 혹은 사이킷런에서 직접구현 가능
from sklearn.model_selection import StratifiedKFold
from sklearn.base import clone
skfolds = StratifiedKFold(n_splits = 3, random_state = 42)
for train_index, test_index in skfolds.split(X_train, y_train_5):
clone_clf = clone(sgd_clf)
X_train_folds = X_train[train_index]
y_train_folds = y_train_5[train_index]
X_test_fold = X_train[test_index]
y_test_fold = y_train_5[test_index]
clone_clf.fit(X_train_folds, y_train_folds)
y_pred = clone_clf.predict(X_test_fold)
n_correct = sum(y_pred == y_test_fold)
print(n_correct / len(y_pred))
- StratifiedKFold : 클래스별 비율이 유지되도록 폴드를 만들기 위해 계층적 샘플링 수행
- 매 반복에서 분류기 객체를 복제하여 훈련 폴드로 훈련, 테스트 폴드로 예측
- 올바른 예측의 수를 세어 정확한 예측의 비율 출력
(+설명 및 코드)
a_a = np.array([[1, 2, 3, 4],
[3, 4, 5, 6],
[1, 2, 3, 4],
[3, 2, 4, 1],
[1, 3, 4, 2],
[2, 1, 4, 3]])
b_b = np.array([1,1,2,2,3,3])
skf = StratifiedKFold(n_splits=2)
for train_index, test_index in skf.split(a_a, b_b):
print("TRAIN:", train_index, "TEST:", test_index)
X_train, X_test = a_a[train_index], a_a[test_index]
y_train, y_test = b_b[train_index], b_b[test_index]
print("train_data")
print(X_train, '\n', y_train)
print("test_data")
print(X_test, '\n', y_test)
클래스별로 샘플의 비율을 동일하게 하기 위하여 총 2번 (n_splits = 2) 나눴고 그 결과 총 2가지의 train & test index가 생성되었다. ( 1. Train : [1, 3, 5] & Test : [0, 2, 4], 2. Train : [0, 2, 4] & Test : [1, 3, 5] )
1의 split을 살펴보자.
a_a의 1, 3, 5번째 인덱스에 해당하는 [3,4,5,6] [3,2,4,1] [2,1,4,3] 과 b_b의 0, 2, 4번째 인덱스에 해당하는 [1, 2, 3] 으로 먼저 분류되었고 마찬가지로 2의 split도 진행되어 결국 클래스별 비율이 동일하게 샘플을 추출한 것을 알 수 있다.
여기서 주의할 점은 n_splits = 변수 하이퍼파라미터를 적절히 잘 지정해야하는데, 만약 각 배열의 크기를 고려하지 않고 지정하게 된다면 오류가 뜬다.
( 6 * 4 , 1 * 6 이므로 6의 공약수로 지정해야한다. n_splits=2 이라면 b_b에 동일한 숫자가 2개씩 존재해야 바람직하다. 즉, 2,2 3,3 4,4 --- 이런식)
위와 같은 방법으로 사이킷런에서는 cross_val_score() 함수를 지원한다. 훈련 세트를 3개 (cv=3)으로 나누는 동일한 교차 검증 세트를 만들어보면
from sklearn.model_selection import cross_val_score
cross_val_score(sgd_clf, X_train, y_train_5, cv=3, scoring="accuracy")
각 폴드 별 정확도가 95% 이상임을 알 수 있다.
모든 이미지를 5 아님 클래스로 분류하는 더미 분류기
from sklearn.base import BaseEstimator
#해당 클래스를 상속하면 *args or **kwargs 가 없어도 자동으로 입력받을 수 있음
class Never5Classifier(BaseEstimator):
def fit(self, X, y=None):
return self
def predict(self, X):
return np.zeros((len(X),1), dtype=bool)
never_5_clf = Never5Classifier()
cross_val_score(never_5_clf, X_train, y_train_5, cv=3, scoring="accuracy")
- Never5Classifier 클래스에 의해 입력되는 X_train내부의 데이터가 모두 [False] 로 변환된다.
- 앞서 만들어놓은 y_train_5와 변환된 X_train을 비교 (cross_val_score) 하여 5가 아닌 값(y_train_5에서 false인 값)의 확률을 계산한다.
3.2 오차 행렬
- 분류기의 성능 평가
- 클래스 A의 샘플이 클래스 B로 분류된 횟수를 세는 것
- 예를 들어, 숫자 5의 이미지를 3으로 잘못 분류한 횟수를 알고 싶다면 오차 행렬의 5행 3열을 확인
- 오차 행렬을 위해 실제 타깃과 비교할 수 있도록 먼저 예측값을 만들어야 함
from sklearn.model_selection import cross_val_predict
y_train_pred = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3)
- cross_val_predict() : cross_val_score()처럼 k-겹 교차 검증 수행 but 각 테스트 폴드에서 얻은 예측 반환 (모든 샘플에 대한 예측)
- confusion_matrix() 로 오차 행렬 생성
from sklearn.metrics import confusion_matrix
confusion_matrix(y_train_5, y_train_pred)
- 행 : 실제 클래스
- 열 : 예측 클래스
- 1행1열 : TN(True Negative), 1행2열 : FP(False Positive) ...
from sklearn.metrics import precision_score, recall_score
from sklearn.metrics import f1_score
precision_score(y_train_5, y_train_pred)
recall_score(y_train_5, y_train_pred)
f1_score(y_train_5, y_train_pred)
(재현율 & 정밀도 & f1 점수)
'핸즈온머신러닝&딥러닝' 카테고리의 다른 글
MNIST 활용, 분류 3 (0) | 2021.05.27 |
---|---|
MNIST 활용, 분류 2 (0) | 2021.05.19 |
캘리포니아 주택 가격 예측2 (0) | 2021.05.16 |
캘리포니아 주택 가격 예측 (0) | 2021.05.15 |
RNN과 어텐션을 사용한 자연어 처리 2 (0) | 2021.05.05 |