본문 바로가기
ML&DATA/핸즈온 머신러닝

3 - 다중분류

by sun__ 2020. 8. 27.

3.4 다중분류

다중분류는 여러 개의 클래스를 분류하는 것을 의미한다. 

 

SGD, randomforest, naive bayes 등의 분류기는 다중 분류가 가능하지만 로지스틱 회귀나 서포트 벡터 머신 분류기같은 알고리즘은 이진 분류만 가능하다.

 

여러 개의 이진 분류기를 사용해서 다중분류를 구현할 수도 있다.

 

OvR(OvA) : one-versus-the rest, 클래스마다 이진 분류기를 만들어서 가장 높은 결정점수를 낸 클래스를 선택

OvO : one-versus-one, 모든 가능한 두 개의 클래스 조합($\frac{n(n-1)}{2}$)에 대해 이진 분류기를 만듦. 가장 많이 양성으로  분류된 클래스 선택

 

OvR : 대부분의 이진 분류 알고리즘이 선호함

OvO : SVM같은 일부 알고리즘은 훈련 세트의 크기에 민감해서 큰 훈련 세트에서 몇 개의 분류기를 훈련시키는 것보다 작은 훈련 세트에서 많은 분류기를 훈련시키는 쪽이 빠르다.

 

다중 클래스 분류 작업에 이진 분류 알고리즘을 선택하면 sklearn이 자동으로 OvR또는 OvO를 실행한다.

 

서포트 벡터 머신으로 테스트해보자. svc는 굉장히 느려서 데이터 개수를 좀 줄여서 해줬다. gamma옵션에 대한 설명은 다음 장에서 서술. some digit을 '5'라고 정확하게 예측해준다.

some_digit, X[0]

from sklearn.svm import SVC
svm_clf = SVC(gamma='auto', random_state=42)
svm_clf.fit(X_train[:1000], y_train[:1000])
svm_clf.predict([some_digit])
#array([5], dtype=uint8)

 

SVC내부에선 OvO 전략을 사용해서 45개의 이진 분류기를 훈련시키고 각각의 결정 점수를 얻어 점수가 가장 높은 클래스를 선택한다. decision_function()을 호출하면 샘플당 10개의 점수를 반환한다. 5의 점수가 9.29로 가장 높은 것을 볼 수 있다.

some_digit_scores = svm_clf.decision_function([some_digit])
some_digit_scores
#array([[ 2.81585438,  7.09167958,  3.82972099,  0.79365551,  5.8885703 ,
#         9.29718395,  1.79862509,  8.10392157, -0.228207  ,  4.83753243]])

 

OvR을 사용하도록 강제하려면 OneVsRestClassifier를 사용한다.(OvO의 경우 OneVsOneClassifier)

이진 분류기 인스턴스를 만들어 객체를 생성할 때 전달하면 된다. SVC 기반으로 OvR 전략을 사용하면 다음과 같다.

from sklearn.multiclass import OneVsRestClassifier
ovr_clf = OneVsRestClassifier(SVC(gamma='auto', random_state=42))
ovr_clf.fit(X_train[:1000], y_train[:1000])
ovr_clf.predict([some_digit])
#array([5], dtype=uint8)

 

SGDClassifier또는 RandomForestClassifier과 같이 다중 분류기를 훈련시키는 것은 그냥 하면 된다.

(X[0]에 대한 예측값이 정확하지 않다.)

sgd_clf.fit(X_train, y_train)
sgd_clf.predict([some_digit])
#array([3], dtype=uint8)
sgd_clf.decision_function([some_digit])
#array([[-31893.03095419, -34419.69069632,  -9530.63950739,
#          1823.73154031, -22320.14822878,  -1385.80478895,
#        -26188.91070951, -16147.51323997,  -4604.35491274,
#        -12050.767298  ]])

 

cross_val_score() 함수로 SGDClassifier의 정확도를 평가해보면 90퍼센트에 근접한 정확도가 나온다. 완전 랜덤한 값을 반환하는 멍청한 분류기의 정확도가 10퍼센트인 것을 생각했을 때 괜찮은 결과인 것 같다.

cross_val_score(sgd_clf, X_train, y_train, cv=3, scoring='accuracy')
#array([0.87082583, 0.87089354, 0.88628294])

 

최근 버전에서 추가된 cross_validate함수는 학습 시간도 같이 반환해준다.

from sklearn.model_selection import cross_validate
cross_validate(sgd_clf, X_train, y_train, cv=3, scoring='accuracy')
#{'fit_time': array([147.28177428, 150.01717424, 158.84921384]),
# 'score_time': array([0.06482244, 0.06478405, 0.05281377]),
# 'test_score': array([0.87082583, 0.87089354, 0.88628294])}

 

입력 벡터를 정규화하여 스케일을 조정하면 정확도를 더 올릴 수 있다.

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train.astype(np.float64))
cross_val_score(sgd_clf, X_train_scaled, y_train, cv=3, scoring='accuracy')
#array([0.89957009, 0.89344467, 0.89963495])

'ML&DATA > 핸즈온 머신러닝' 카테고리의 다른 글

4 - 선형 회귀 (정규방정식)  (0) 2020.09.04
3 - 다중 레이블 분류, 다중 출력 분류  (2) 2020.08.27
3 - 에러분석  (0) 2020.08.27
3 - 분류기의 성능 측정  (0) 2020.08.25
개요  (2) 2020.07.16