chapter 3 - 분류 / 3.1, 3.2

inxnxng·2021년 1월 25일
0

노션 정리 : https://www.notion.so/bmo29/chapter-3-0b3c96ef54fc492aa5bbbff553dc8312


1장에서 가장 일반적인 지도 학습 작업이 회귀(값 예측)와 분류(클래스 예측) 이라고 했고, 2장에서는 주택 가격을 예측하는 회귀 작업을 살펴보면서 선형 회귀, 결정 트리, 랜덤 포레스트와 같은 알고리즘을 살펴 보았다. 3장에서는 분류 시스템에 대해 배워본다.

3.1 MNIST

레이블이 되어 있는 각 이미지 데이터 셋을 학습용 이미지로 가져오자.

from sklearn.datasets import fetch_openml
mnist = fetch_openml('mnist_784', version=1)
mnist.keys()

사이킷런에서 읽어들인 데이터들은 딕셔너리 구조를 가진다.

  • 데이터를 설명하는 DESCR
  • 샘플이 하나의 행, 특성이 하나의 열로 구성된 배열을 가진 data
  • 레이블 배열을 담은 target

이미지가 70,000개 있고 각 이미지에는 784개의 특성이 존재한다. (이미지가 28 X 28 픽셀이기 때문.)

객체의 특성은 0(흰색) 255(검은색)까지의 픽셀 강도를 나타낸다.

import matplotlib as mpl
import matplotlib.pyplot as plt

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

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

y[0] 을 입력하면 실제 레이블이 5로 되어있는 것을 확인할 수 있다. 레이블은 문자열이다. 머신러닝 알고리즘에서는 숫자를 기대하므로 astype 를 통해 y를 정수로 변환한다.

데이터를 조사하기 전에 항상 훈련 세트와 테스트 세트를 분리해놓는 것을 잊지 말자.

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

훈련세트는 이미 섞여있어서 모든 교차 검증 fold를 비슷하게 만든다.

3.2 이진 분류기 훈련

문제를 단순화하여 하나의 숫자 (예를 들어 5)만 식별한다고 하자. '5-감지기'는 5와 5 아님의 2개의 클래스를 구분할 수 있는 이진 분류기 ; binary classifier 의 한 예가 된다.

y_train_5 = (y_train == 5) # 5는 True이고 나머지는 False
y_test_5 = (y_test == 5)

사이킷런의 SGDClassifier 클래스를 사용하여 확률적 경사 하강법 ; Stochastic Gradient Descent(SGD) 분류기로 시작해보자. 이는 한 번에 하나씩 훈련 샘플을 독립적으로 처리하기 때문에 매우 큰 데이터셋을 효율적으로 처리한다.

모델을 먼저 만들고 전체 훈련 세트를 사용해 훈련한다.

from sklearn.linear_model import SGDClassifier

sgd_clf = SGDClassifier(random_state=42)
sgd_clf.fit(X_train, y_train_5)

SGDClassifier는 훈련하는데 무작위성을 사용하므로 이름에 확률적이라는 단어가 붙은 것이다.

클래스를 생성하고 .fit() 을 통해 X_trainy_train_5 를 넣어준다. y_train_5 를 넣어줌으로 인해 분류 기능을 추가시킨 것이다.

some_digitX[0] 이다. True로 나온 것이 맞다.

X[4] 는 9이므로 False로 나오는 것이 맞다.

3.3 성능 측정

분류기 평가는 회귀 모델보다 훨씬 어렵다. 따라서 사용할 수 있는 성능 지표가 많다.

3.3.1 교차 검층을 사용한 정확도 측정

교차 검증 구현을 사이킷런의 cross_val_score() 을 통해 구현할 수 있다.

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 는 클래스별 비율이 유지되도록 폴드를 만들기 위해 계층적 샘플링을 수행한다. 매 반복에서 분류기 객체를 복제하여 훈련 폴드로 훈련하고(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)).

k-겹 교차 검증은 훈련 세트를 k개의 폴드로 나누고 각 폴드에 대해 예측을 만들고 평가하기 위해 나머지 폴드로 훈련시킨 모델을 사용한다.

from sklearn.model_selection import cross_val_score
cross_val_score(sgd_clf, X_train, y_train_5, cv = 3, scoring = "accuracy")
from sklearn.base import BaseEstimator
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")

숫자 10개 중에 1개가 5이니까 나머지 5가 아닌 집단은 90%가 맞다.

정확도를 분류기의 성능 측정 지표로 선호하지 않는 이유를 보여준다. 트기 불균형한 데이터셋 을 다룰 때 (즉, 어떤 클래스가 다른 것보다 월등히 많은 경우) 특히 그렇다.

0개의 댓글