[ML] Multi* Classification

shihyunlim·2024년 9월 23일

Machine Learning

목록 보기
15/20

https://velog.io/@shihyunlim/ML-Multiclass-Classification
이전에 공부했던 내용이라 이번에는 코드 위주로 공부하려 함

Multiclass Classifier

  • Multiclass classifier(다중 분류기) 또는 Multinomial classifier(다항 분류기)
  • 이진 분류기를 여러 개 사용해서 다중 분류 ㄱㄴ
    -> OvA 또는 OvR, OvO 자동으로 선택되지만, 강제로 지정할 수 있음
from sklearn.svm import SVC # SVMClassifier로 원래는 이진 분류만 가능
svm_clf = SVC(random_state=42)
svm_clf.fit(X_train[:2000], y_train[:2000]) # 자동으로 OvO 실행해서 다중 분류함

svm_clf.predict([some_digit])

some_digit_scores = svm_clf.decision_function([some_digit])
some_digit_scores.round(2)
# 출력: array([[ 3.79,  0.73,  6.06,  8.3 , -0.29,  9.3 ,  1.75,  2.77,  7.21,  4.82]])
# decision_function()으로 샘플마다 10개의 점수 반환. 각 클래스는 분류기 점수를 기반으로 각 쌍에서 이긴 횟수에 약간의 조정 값(최대 +-0.33)을 추가하여 동률 문제 해결

class_id = some_digit_scores.argmax() # 점수가 가장 높은 인덱스 반환
class_id

svm_clf.classes_ # 타깃 클래스(값) 정렬

svm_clf.classes_[class_id]

from sklearn.multiclass import OneVsRestClassifier
ovr_clf = OneVsRestClassifier(SVC(random_state=42)) # SVC를 OvR에 넣음. 강제로 지정한 것
ovr_clf.fit(X_train[:2000], y_train[:2000]) # SVM이라서 데이터 일부만 가지고 테스트. 아니면 너무 오래걸릴 것이라고 함. -> SVM 관련 내용은 챕터 5에 나옴. 그때 알게 되겠지?

ovr_clf.predict([some_digit])

len(ovr_clf.estimators_) # 훈련된 분류기 수

# 여기부터는 SGDClassifier 이용. SVC와 마찬가지로 원래는 이진 분류에만 사용
sgd_clf = SGDClassifier(random_state=42) # OvR로 다중 분류함
sgd_clf.fit(X_train, y_train)
sgd_clf.predict([some_digit])

sgd_clf.decision_function([some_digit]).round()
# 출력: array([[-31893., -34420.,  -9531.,   1824., -22320.,  -1386., -26189.,  -16148.,  -4604., -12051.]]) 

cross_val_score(sgd_clf, X_train, y_train, cv=3, scoring="accuracy")
# 출력: array([0.87365, 0.85835, 0.8689 ])

from sklearn.preprocessing import StandardScaler # 스케일링으로 모델 성능 높여보기
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train.astype("float64"))
cross_val_score(sgd_clf, X_train_scaled, y_train, cv=3, scoring="accuracy")
# 출력: array([0.8983, 0.891 , 0.9018])

*앞의 decision_function은 이진 분류만을 예로 들어서 다중 분류의 경우 출력을 어떻게 해석해야 하는지 의문이 들었음. 절대값이 크다는 건 강한 확신이라는 건 알겠는데, 양수랑 음수는 도대체 뭐지 싶었음
-> 그런데 사실 아까 얘기했던 거랑 다를 게 없음. 양수 값(=양성 클래스 =1)은 해당 샘플이 래당 클래스에 속할 확률이 높다는 것이고 음수 값(=음성 클래스 =0)은 해당 샘플이 해당 클래스에 속할 가능성이 낮다는 의미!

Error Analysis

  • 가능성이 높은 모델 하나를 찾았다고 가정하고 모델을 향상시키는 방법으로 오류 분석을 택함
  • 대각선에 있는 셀이 올바르게 분류된 값들임
  • 매개변수 normalize="true"로 하여 정규화 ㄱㄴ
    -> 각 값을 해당 클래스(=True label =행의 합)의 총 이미지 수로 나누는 것
    -> 더 많은 오류가 있거나 데이터 집합의 수가 다른 레이블에 비해 적은 경우 잘못 판단될 위험 있으므로 해주는 게 좋음
  • normalize="pred"로 지정하면 열 단위 정규화 ㄱㄴ

Multilabel Classification

  • 샘플마다 여러 클래스를 출력하는 경우. 여러 개의 이진 꼬리표를 출력하는 경우
  • 예) 모델이 앨리스, 밥, 찰리 세 명의 얼굴을 인식하도록 훈련되었다고 가정. 분류기가 앨리스와 찰리가 같이 있는 사진을 보면 [1, 0, 1]을 예측할 것임
import numpy as np
from sklearn.neighbors import KNeighborsClassifier

y_train_large = (y_train >= '7') # 7 이상인 경우 true
y_train_odd = (y_train.astype('int8')%2==1) # 홀수인 경우 true
y_multilabel = np.c_[y_train_large, y_train_odd] # 다중 라벨 생성
knn_clf = KNeighborsClassifier() # KNN은 다중 레이블 분류 지원됨
knn_clf.fit(X_train, y_multilabel)

knn_clf.predict([some_digit])

y_train_knn_pred = cross_val_predict(knn_clf, X_train, y_multilabel, cv=3)
f1_score(y_multilabel, y_train_knn_pred, average="macro") # 레이블에 대한 예측 결과를 평균낸 값
# average="weighted"로 지정하면 타깃 레이블에 속한 샘플 수를 기반으로 점수에 높은 가중치를 줄 수 있음

from sklearn.multioutput import ClassifierChain # 다중 라벨을 지원하지 않는 분류기를 사용한 경우 예) SVC
chain_clf = ClassifierChain(SVC(), cv=3, random_state=42)
chain_clf.fit(X_train[:2000], y_multilabel[:2000])

chain_clf.predict([some_digit])

Multioutput Classification

  • Multioutput-Multiclass Classification 또는 Multioutput Classification(다중 출력 분류)
  • 다중 레이블에서 한 레이블이 다중 클래스를 가지는 경우
  • 예) 이미지에서 잡음을 제거하는 시스템: 28*28 크기의 이미지에서 각 필셀 별로 노이즈를 제거함(픽셀 강도는 0~255임)
# 훈련 데이터와 테스트 데이터에 노이즈 추가
# 특성(X)은 노이즈를 추가한 이미지고, 타깃(y)은 깨끗한 이미지임
np.random.seed(42)
noise = np.random.randint(0, 100, (len(X_train), 784))
X_train_mod = X_train + noise
noise = np.random.randint(0, 100, (len(X_test), 784))
X_test_mod = X_test + noise
y_train_mod = X_train
y_test_mod = X_test

knn_clf = KNeighborsClassifier()
knn_clf.fit(X_train_mod, y_train_mod)
clean_digit = knn_clf.predict([X_test_mod[0]])
plot_digit(clean_digit)
plt.show()

출처: 핸즈온 머신러닝 3판

0개의 댓글