https://velog.io/@shihyunlim/ML-Multiclass-Classification
이전에 공부했던 내용이라 이번에는 코드 위주로 공부하려 함
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)은 해당 샘플이 해당 클래스에 속할 가능성이 낮다는 의미!



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])
# 훈련 데이터와 테스트 데이터에 노이즈 추가
# 특성(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판