# 공통 모듈 임포트
import numpy as np
import os
# mnist 데이터 불러오기
from sklearn.datasets import fetch_openml
mnist = fetch_openml('mnist_784', version=1)
C:\Users\20229069\AppData\Local\anaconda3\Lib\site-packages\sklearn\datasets\_openml.py:1002: FutureWarning: The default value of `parser` will change from `'liac-arff'` to `'auto'` in 1.4. You can set `parser='auto'` to silence this warning. Therefore, an `ImportError` will be raised from 1.4 if the dataset is dense and pandas is not installed. Note that the pandas parser may return different data types. See the Notes Section in fetch_openml's API doc for details. warn(
X, y = mnist["data"], mnist["target"]
X.shape
(70000, 784)
y.shape
(70000,)
# 0행의 그림
%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt
some_digit = X.loc[[0]]
some_digit = some_digit.to_numpy()
some_digit_image = some_digit.reshape(28, 28)
plt.imshow(some_digit_image, cmap=mpl.cm.binary)
plt.axis("off")
plt.show()
# 0행의 값
y[0]
'5'
3.2 이진 분류기 훈련¶
- 사이킷런의 SGDClassifier 활률적 경사 하강법(SGD) 사용, 매우 큰 데이터셋을 효율적으로 처리하는데 장점
y = y.astype(np.uint8)
# 훈련 세트와 테스트 세트
X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:]
# 10개 숫자 들어있는지 확인
y_train.value_counts()
1 6742 7 6265 3 6131 2 5958 9 5949 0 5923 6 5918 8 5851 4 5842 5 5421 Name: class, dtype: int64
y_train_5 = (y_train == 5)
y_test_5 = (y_test == 5)
# SGDClassifier 훈련
from sklearn.linear_model import SGDClassifier
sgd_clf = SGDClassifier(random_state=42)
sgd_clf.fit(X_train, y_train_5)
SGDClassifier(random_state=42)In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
SGDClassifier(random_state=42)
# 예측
from sklearn.model_selection import cross_val_score
cross_val_score(sgd_clf, X_train, y_train_5, cv=3, scoring="accuracy")
array([0.95035, 0.96035, 0.9604 ])
3.3 성능 측정¶
교차 검증은 모델을 평가하는 좋은 방법
불균형한 데이터셋을 다룰 때 정확도는 성능 측정 지표로 선호하지 않습니다.
분류기의 성능을 평가하는 더 좋은 방법은 오차 행렬을 조사하는 것입니다.
오차 행렬의 행은 실제 클래스를 나타내고 열은 예측한 클래스를 나타냅니다.
완벽한 분류기라면 진짜 양성과 진짜 음성만 가지고 있는 행렬의 주대각선만 0이 아닌 값이 됩니다.
F1 점수는 정밀도와 재현율의 조화 평균(식 : 2(정밀도재현율)/(정밀도+재현율))
정밀도를 올리면 재현율이 줄고 그 반대도 마찬가지인 정밀도/재현율 트레이드오프 발생
from sklearn.model_selection import cross_val_predict
y_train_pred = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3)
from sklearn.metrics import confusion_matrix
confusion_matrix(y_train_5, y_train_pred)
array([[53892, 687], [ 1891, 3530]], dtype=int64)
# 오차 행렬 값 추출
from sklearn.metrics import precision_score, recall_score
print("정밀도 : {:.2f}" .format(precision_score(y_train_5, y_train_pred))) # 정밀도 구하는 코드
print("재현율 : {:.2f}" .format(recall_score(y_train_5, y_train_pred))) # 재현율 구하는 코드
from sklearn.metrics import f1_score
print("F1 값 : {:.2f}" .format(f1_score(y_train_5, y_train_pred))) # F1값 구하는 코드
정밀도 : 0.84 재현율 : 0.65 F1 값 : 0.73
# 모든 결정 점수 값 추출
y_scores = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3,
method="decision_function")
from sklearn.metrics import precision_recall_curve
precisions, recalls, thresholds = precision_recall_curve(y_train_5, y_scores)
def plot_precision_recall_vs_threshold(precisions, recalls, thresholds):
plt.plot(thresholds, precisions[:-1], "b--", label="Precision", linewidth=2)
plt.plot(thresholds, recalls[:-1], "g-", label="Recall", linewidth=2)
plt.legend(loc="center right", fontsize=16) # Not shown in the book
plt.xlabel("Threshold", fontsize=16) # Not shown
plt.grid(True) # Not shown
plt.axis([-50000, 50000, 0, 1]) # Not shown
recall_90_precision = recalls[np.argmax(precisions >= 0.90)]
threshold_90_precision = thresholds[np.argmax(precisions >= 0.90)]
plt.figure(figsize=(8, 4)) # Not shown
plot_precision_recall_vs_threshold(precisions, recalls, thresholds)
plt.plot([threshold_90_precision, threshold_90_precision], [0., 0.9], "r:") # Not shown
plt.plot([-50000, threshold_90_precision], [0.9, 0.9], "r:") # Not shown
plt.plot([-50000, threshold_90_precision], [recall_90_precision, recall_90_precision], "r:")# Not shown
plt.plot([threshold_90_precision], [0.9], "ro") # Not shown
plt.plot([threshold_90_precision], [recall_90_precision], "ro") # Not shown
plt.show()
# 정밀도/재현율 트레이드오프 그래프
def plot_precision_vs_recall(precisions, recalls):
plt.plot(recalls, precisions, "b-", linewidth=2)
plt.xlabel("Recall", fontsize=16)
plt.ylabel("Precision", fontsize=16)
plt.axis([0, 1, 0, 1])
plt.grid(True)
plt.figure(figsize=(8, 6))
plot_precision_vs_recall(precisions, recalls)
plt.plot([recall_90_precision, recall_90_precision], [0., 0.9], "r:")
plt.plot([0.0, recall_90_precision], [0.9, 0.9], "r:")
plt.plot([recall_90_precision], [0.9], "ro")
plt.show()
- 재현율 80% 근처에서 정밀도가 급격하게 줄어들기 시작하며 이 하강점 직전을 정밀도/재현율 트레이드오프로 선택하는 것이 일반적으로 좋습니다.
3.3.5 ROC 곡선¶
수신기 조작 특성(ROC)은 정밀도에 대한 재현율 곡선이 아니고 거짓 양성 비율(FPR)에 대한 진짜 양성 비율(TPR)의 곡선입니다.
진짜 음성 비율(TNR)을 특이도라고 하며 FPR은 1에서 TNR를 뺸 값입니다. 그러므로 ROC 곡선은 민감도(재현율)에 대한 1-특이도 그래프입니다.
재현율(TPR)이 높을수록 분류기가 만드는 거짓 양성(FPR)이 늘어납니다.
ROC 곡선 아래의 면적(AUC)을 측정하면 분류기를 비교할 수 있으며 완벽한 분류기는 AUC가 1이고, 완전 랜덤한 분류기는 0.5입니다.
일반적인 법칙은 양성 클래스가 들물거나 거짓 음성보다 거짓 양성이 더 중요할 때 PR 곡선을 사용하고 그렇지 않으면 ROC 곡선을 사용합니다.
from sklearn.metrics import roc_curve
from sklearn.ensemble import RandomForestClassifier
forest_clf = RandomForestClassifier(n_estimators=100, random_state=42)
y_probas_forest = cross_val_predict(forest_clf, X_train, y_train_5, cv=3,
method="predict_proba")
y_scores_forest = y_probas_forest[:, 1] # 점수 = 양성 클래스의 확률
fpr_forest, tpr_forest, thresholds_forest = roc_curve(y_train_5,y_scores_forest)
def plot_roc_curve(fpr, tpr, label=None):
plt.plot(fpr, tpr, linewidth=2, label=label)
plt.plot([0, 1], [0, 1], 'k--') # 대각 점선
plt.axis([0, 1, 0, 1]) # Not shown in the book
plt.xlabel('False Positive Rate (Fall-Out)', fontsize=16) # Not shown
plt.ylabel('True Positive Rate (Recall)', fontsize=16) # Not shown
plt.grid(True)
# SGD와 랜덤포레스트 ROC 성능 비교
fpr, tpr, thresholds = roc_curve(y_train_5, y_scores)
plt.figure(figsize=(8, 6))
plt.plot(fpr, tpr, "b:", linewidth=2, label="SGD")
plot_roc_curve(fpr_forest, tpr_forest, "Random Forest")
plt.legend(loc="lower right", fontsize=16)
plt.show()
3.4 다중 분류¶
둘 이상의 클래스를 구별하는 것을 다중 분류기(다항 분류기)라고 한다.
(SGD, 랜덤 포레스트, 나이브 베이즈) 일부 알고리즘은 여러 개의 클래스를 직접 처리할 수 있는 반면, (로지스틱 회귀, 서포트 벡터 머신) 다른 알고리즘은 이진 분류만 가능합니다. 하지만 이진 분류기를 여러 개 사용해 다중 클래스를 분류하는 기법도 존재
OvR 전략 : 분류기의 결정 점수 중에서 가장 높은 것을 클래스로 선택
OvO 전략 : 각 숫자의 조합마다 이진 분류기를 훈련시키는 것(N개 클래스라면 분류기는 N*(N-1)/2개 필요)
사이킷런에서 OvO나 OvR을 사용하도록 강제하려면 OneVsOneClassifier나 OneVsRestClassifier를 사용
3.5 에러 분석¶
- 오차 행렬을 분석하면 분류기의 성능 향상 방안에 대한 통창을 얻을 수 있습니다.
3.6 다중 레이블 분류¶
- 여러 개의 이진 꼬리표를 출력하는 분류 시스템을 다중 레이블 분류 시스템이라고 합니다.
3.7 다중 출력 분류¶
- 한 레이블이 다중 클래스가 될 수 있도록 일반화하는 것
from IPython.core.display import display, HTML
display(HTML("<style>.container {width:80% !important;}</style>"))
C:\Users\20229069\AppData\Local\Temp\ipykernel_18208\529043151.py:1: DeprecationWarning: Importing display from IPython.core.display is deprecated since IPython 7.14, please import from IPython display from IPython.core.display import display, HTML
'Book report > 핸즈온 머신러닝' 카테고리의 다른 글
[핸즈온 머신러닝] Chapter 6. 결정 트리 (0) | 2024.04.01 |
---|---|
[핸즈온 머신러닝] Chapter 5. 서포트 벡터 머신 (0) | 2023.09.12 |
[핸즈온 머신러닝] Chapter 4. 모델 훈련 (0) | 2023.09.06 |
[핸즈온 머신러닝] Chapter 2. 머신러닝 프로젝트 처음부터 끝까지 (0) | 2023.08.04 |
[핸즈온 머신러닝] Chapter 1. 한눈에 보는 머신러닝 (0) | 2023.07.26 |