MNIST 데이터셋 분류
1. MNIST
사이킷런에서 제공하는 여러 헬퍼 함수를 사용해 MNIST 데이터셋을 내려받을 수 있습니다.
Code
from sklearn.datasets import fetch_mldata
X, y = mnist["data"], mnist["target"]
print(X.shape)
print(y.shape)
Output
이미지가 70,000개가 있고 각 이미지에는 784개의 특성이 있습니다. 이미지가 28 × 28 픽셀이기 때문입니다.
개개의 특성은 단순히 0(흰색) 부터 255 (검은색) 까지의 픽셀 강도를 나타냅니다.
데이터셋에서 이미지 하나를 확인해보도록 하겠습니다. 샘플의 특성 벡터를 추출해서 28 × 28 배열로 크기를 바꾸고 맷플롯립의 imshow() 함수를 활용합니다.
Code
import matplotlib
import matplotlib.pyplot as plt
some_digit = X[36000]
some_digit_image = some_digit.reshape(28, 28)
plt.imshow(some_digit_image, cmap=matplotlib.cm.binary,
interpolation="nearest")
plt.axis("off") plt.show() print(y[36000])
Output
>> 5.0
그림 상으로 숫자 '5' 처럼 보이는데, 실제 레이블을 확인해보니 5.0으로 나타납니다.
데이터를 분석하기 전 테스트 세트를 만들고 시작하도록 하겠습니다. MNIST 데이터셋의 경우 이미 훈련 세트(앞쪽 60,000개)와 테스트 세트(뒤쪽 10,000)로 나누어져 있습니다.
Code
import numpy as np
X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:]
shuffle_index = np.random.permutation(60000)
X_train, y_train = X_train[shuffle_index], y_train[shuffle_index]
훈련 세트를 섞어 모든 교차 검증 폴드가 비슷해지도록 만들었습니다. 특정 학습 알고리즘은 훈련 샘플의 순서에 민감하게 반응해서 많은 비슷한 샘플이 연이어 나타나면 성능이 나빠집니다. 데이터셋을 섞으면 이러한 문제를 방지할 수 있습니다.
2. 이진 데이터 훈련
Code
from sklearn.linear_model import SGDClassifier
y_train_5 = (y_train == 5)
y_test_5 = (y_test == 5)
sgd_clf = SGDClassifier(max_iter=5, random_state=42)
sgd_clf.fit(X_train, y_train_5)
print(sgd_clf.predict([some_digit]))
y_test_5 = (y_test == 5)
sgd_clf = SGDClassifier(max_iter=5, random_state=42)
sgd_clf.fit(X_train, y_train_5)
print(sgd_clf.predict([some_digit]))
Output
3. 성능 측정
3.1 교차 검증을 사용한 정확도 측정
StratifiedKFold는 클래스별 비율이 유지되도록 폴드를 만들기 위해 계층적 샘플링을 수행합니다. 매 반복에서 분류기 객체를 복제하여 훈련 폴드로 훈련시키고 테스트 폴드로 예측을 만듭니다. 이후 올바른 예측 수를 세어 정확한 예측의 비율을 출력합니다.
Code
from sklearn.linear_model import SGDClassifier
from sklearn.model_selection import StratifiedKFold
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))
Output
사이킷런의 cross_val_score() 함수를 사용하여 폴드가 3개인 K-겹 교차 검증을 사용해 SGDClassifier 모델을 평가해보겠습니다. K-겹 교차 검증은 훈련 세트를 K개의 폴드로 나누고, 각 폴드에 대해 예측을 만들고 평가하기 위해 나머지 폴드로 훈련시킨 모델을 사용합니다.
Code
from sklearn.model_selection import cross_val_score
print(cross_val_score(sgd_clf, X_train, y_train_5, cv=3, scoring="accuracy"))
Output
모든 교차 검증 폴드에 대해 정확도(Accuracy)가 95% 이상임을 확인할 수 있습니다.
그렇다면, 모든 이미지를 '5가 아님' 클래스로 분류하는 더미 분류기를 만들어 성능을 비교해보도록 하겠습니다.
Code
from sklearn.base import BaseEstimator
class Never5Classifier(BaseEstimator):
def fit(self, X, y=None):
pass
def predict(self, X):
return np.zeros((len(X), 1), dtype=bool)
never_5_clf = Never5Classifier()
print(cross_val_score(never_5_clf, X_train, y_train_5, cv=3, scoring="accuracy"))
Output
정확도가 90% 이상 나오는 것을 확인할 수 있습니다만, 숫자 '5'를 분류할 때보다 성능이 떨어지는 것을 확인할 수 있었습니다.
이 예제는 정확도를 분류기의 성능 지표로 선호하지 않는 이유를 보여줍니다. 특히 불균형한 데이터셋을 다룰 때 더욱 그렇습니다.
References
- 오렐리앙 제롱, '핸즈온 머신러닝', 한빛미디어, 2018
'Machine Learning > Basic Theory' 카테고리의 다른 글
[ML] 머신 러닝에서 확장성이란? (0) | 2018.12.19 |
---|---|
[ML] MNIST 데이터셋 분류 - 오차 행렬 (0) | 2018.08.31 |
[ML] 머신러닝 알고리즘을 위한 특성 스케일링 (0) | 2018.08.31 |
[ML] 머신러닝 알고리즘을 위한 데이터 준비 (0) | 2018.08.31 |
[ML] 머신러닝을 위한 테스트 세트 만들기 (2) | 2018.08.31 |