반응형
- 참고 : 핸즈온 머신러닝 2판
이진 분류기
- mnist를 활용한 5, 5아님 분류기
- sklearn의 SGDClassifier 모델 사용
- SGD (확률적 경사 하강법)은 매우 큰 데이터셋을 효율적으로 처리하는 장점을 가짐
- SGD는 한번에 하나씩 훈련 샘플을 독립적으로 처리함
from sklearn.linear_model import SGDClassifier
sgd_clf = SGDClassifier(max_iter=1000, tol=1e-3, random_state=42)
sgd_clf.fit(X_train, y_train_5)
SGDClassifier은 훈련하는데 무작위성을 사용
성능 측정
- 교차 검증
- skleran의 cross_val_score 함수와 유사한 작업 수행하는 예시
from sklearn.model_selection import StratifiedKFold
from sklearn.base import clone
# shuffle=False가 기본값이기 때문에 random_state를 삭제하던지 shuffle=True로 지정하라는 경고가 발생합니다.
# 0.24버전부터는 에러가 발생할 예정이므로 향후 버전을 위해 shuffle=True을 지정합니다.
skfolds = StratifiedKFold(n_splits=3, random_state=42, shuffle=True)
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))
위 과정을 cross_val_score로 표현하면
- cross_val_score() 함수로 폴드가 3개인 k-겹 교차 검증을 사용해 SGDClassifier 평가
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):
pass
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")
>>> array([0.91125, 0.90855, 0.90915])
- 아무런 학습을 수행하지 않아도 정확도 90% 이상
- 불균형 데이터셋을 다룰때 이러한 분류 성능 문제가 발생
오차 행렬
- 분류기의 성능을 평가하는 방법
- cross_val_predict() 함수를 통해 사용가능
- cross_val_score 함수처럼 cross_val_predict 함수는 k-겹 교차 검증을 수행하지만 평가 점수를 반환하지 않고 각 테스트 폴드에서 얻은 예측을 반환
from sklearn.model_selection import cross_val_predict
y_train_pred = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3)
오차 행렬
- 오차 행렬의 행은 실제 클래스를 의미, 열은 예측한 클래스를 의미
- 밑의 결과의 첫 행은 '5 아님' 이미지에 대한 것 53892개를 '5 아님'으로 정확하게 판단, 687을 5라고 잘못 판단
- 두번째 행은 5에 대한 이미지, 1891을 5아님으로 잘못 판단, 3530을 5라고 맞게 판단
from sklearn.metrics import confusion_matrix
confusion_matrix(y_train_5, y_train_pred)
>> array([[53892, 687],
[ 1891, 3530]])
- 오차 행렬은 많은 정보를 제공하지만 요약된 지표를 통해 빠르게 판단해야 하는 상황이 필요함
정밀도(Precision)
- 예측을 Positive로 한 대상(FP + TP) 중 예측과 실제 값이 Positive로 일치한 데이터(TP)의 비율
- TP / (FP + TP) (TP : 진짜 양성의 수, FP : 가짜 양성의 수)
재현율(Recall)
- 실제가 Positive인 대상(FN + TP) 중 예측과 실제 값이 Positive로 일치한 데이터(TP)의 비율
- TP / (FN + TP)
- 민감도 라고도 함
정밀도와 재현율
from sklearn.metrics import precision_score, recall_score
# 정밀도
precision_score(y_train_5, y_train_pred)
>> 0.8370879772350012
# 재현율
recall_score(y_train_5, y_train_pred)
>> 0.6511713705958311
- 전체 5로 판단한 이미지 중에서 83% 정확함
- 전체 숫자 5중에서 65% 정확함
- 정밀도와 재현률을 F1 score라고 하는 하나의 값으로 판단, 정밀도와 재현율의 조화 평균
from sklearn.metrics import f1_score
f1_score(y_train_5, y_train_pred)
>> 0.7325171197343846
- 상황에 따라서 정밀도가 중요한지 재현율이 중요한지 기준이 바뀜
정밀도/재현율 트레이드오프
- 임계값을 내리면 재현율이 높아지고 정밀도가 줄어듦
- 임계값을 올리면 재현율은 줄어들고 정밀도는 높아짐
- 분류기의 predict 대신 decision_function을 통해 각 셈플의 점수를 얻을수 있음, 이를 통해 원하는 임계값 설정 가능
y_scores = sgd_clf.decision_function([some_digit]) # some_digit는 5의 이미지
y_scores
>> array([2164.22030239])
# 위의 기준값을 통해 적절한 임계값을 설정할수 있지만 cross_val_predict()를 통해 수행가능
cross_val_predict()
- 훈련 세트에 있는 모든 샘플의 점수를 구함
- 예측 결과가 아닌 결정 점수를 반환 받도록 지정
y_scores = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3,
method="decision_function")
- 위의 y_scores를 통해 가능한 모든 임계값에 대해 정밀도와 재현율을 계산할수 있음
from sklearn.metrics import precision_recall_curve
precisions, recalls, thresholds = precision_recall_curve(y_train_5, y_scores)
- precision_recall_curve를 통해 트레이드 오프 그래프 그리기
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
plot_precision_recall_vs_threshold(precisions, recalls, thresholds)
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")
save_fig("precision_vs_recall_plot")
plt.show()
- 만약 정밀도 90%가 목표라면 np.argmax() 사용
# precisions 이 90% 넘을때 그때의 임계값
threshold_90_precision = thresholds[np.argmax(precisions >= 0.90)]
# 임계값을 넘는 y 값만 선택
y_train_pred_90 = (y_scores >= threshold_90_precision)
precision_score(y_train_5, y_train_pred_90)
>> 0.9
recall_score(y_train_5, y_train_pred_90)
>> 0.47
ROC 곡선
- 이진 분류에서 사용하는 정밀도/재현률 곡선과 매우 유사한 곡선
- ROC 곡선은 정밀도에 대한 재현율 곡선이 아니고 거짓 양성 비율에 대한 진짜 양성비율의 곡선
- ROC 곡선은 재현율에 대한 1-특이도 그래프
- ROC 곡선을 그리기 위해서는 여러 임계값에서의 TPR, FPR을 계산
from sklearn.metrics import roc_curve
# fpr, tpr 값 얻음
fpr, tpr, thresholds = roc_curve(y_train_5, y_scores)
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) # Not shown
plt.figure(figsize=(8, 6)) # Not shown
plot_roc_curve(fpr, tpr)
fpr_90 = fpr[np.argmax(tpr >= recall_90_precision)] # Not shown
plt.plot([fpr_90, fpr_90], [0., recall_90_precision], "r:") # Not shown
plt.plot([0.0, fpr_90], [recall_90_precision, recall_90_precision], "r:") # Not shown
plt.plot([fpr_90], [recall_90_precision], "ro") # Not shown
save_fig("roc_curve_plot") # Not shown
plt.show()
- 좋은 분류기는 점선에서 가장 멀리 떨어져있는 지점
from sklearn.metrics import roc_auc_score
roc_auc_score(y_train_5, y_scores)
>> 0.96
RandomForestClassifier 를 통한 ROC, ROC_AUC 비교
- random forest 는 predict_proba 메서드가 존재
- 샘플이 행, 클래스가 열 -> 주어진 클래스에 속할 확률을 담은 배열을 반환
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")
# 양성 클래스에 대한 확률을 점수로 사용, roc_curve 를 통한 fpr, tpr 생성
y_scores_forest = y_probas_forest[:, 1]
fpr_forest, tpr_forest, thresholds_forest = roc_curve(y_train_5,y_scores_forest)
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()
roc_auc_score(y_train_5, y_scores_forest)
>> 0.99
y_train_pred_forest = cross_val_predict(forest_clf, X_train, y_train_5, cv=3)
precision_score(y_train_5, y_train_pred_forest)
>> 0.99
recall_score(y_train_5, y_train_pred_forest)
>> 0.86
다중 분류
- 둘 이상의 클래스를 구별
- SGD, randomforest, naive bayes 분류기는 다중 분류 가능
- 로지스틱 회귀나 서포트 벡터 머신 분류기등은 이진 분류만 가능
이진 분류기를 여러 개 사용해 다중 분류로 활용 가능
-> OVR(각 분류기의 결정 점수 중에서 가장 높은 것을 선택)
-> OVO(각 이미지의 조합마다 이진 분류기를 훈련시키는 것, class가 n개일시 N x (N-1) / 2 개 필요)
다중 클래스 분류 작업에 이진 분류 알고리즘을 사용하면 sklearn이 알고리즘에 따라서 OvR, OvO를 실행
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)
- 이 경우에 이진 분류기를 통한 다중분류를 수행했기 때문에 OvO 전략으로 10개의 이진 분류기를 훈련, 각각의 결정 점수를 얻어 점수가 가장 높은 클래스 선택
- decision_function을 통한 각 샘플의 점수 반환 (10개가 반환)
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]])
# 가장 높은 샘플 점수
np.argmax(some_digit_scores)
>> 5
# 클래스 호출
svm_clf.classes_
>> array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=uint8)
# 가장 높은 샘플점수가 5번 즉 5번 class의 점수가 제일 높음 (some_digit = 5)
- OvR, OvO 같은 방법을 강제하는 법은 OneVsOneClassifier, OneVsRestClassifier를 사용
- 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)
# 생성된 분류기 개수
len(ovr_clf.estimators_)
>> 10
- SGDClassifier 훈련
sgd_clf.fit(X_train, y_train)
sgd_clf.predict([some_digit])
# 클래스 마다의 샘플 값
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 ]])
- SGDClassifier는 다중클래스 분류가 가능하기 때문에 별도의 OvR, OvO를 적용할 필요가 없음
- 5, 3 에 대한 sample 값만 양수 조금더 세밀하게 파악하기 위해 cross_val_score() 사용해 정확도 평가
cross_val_score(sgd_clf, X_train, y_train, cv=3, scoring="accuracy")
>> array([0.87365, 0.85835, 0.8689])
모든 성능이 84% 이상, scale 적용시 성능이 더 높아질 여지가 있음
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.8983, 0.891 , 0.9018])
에러 분석
- 이진 분류와 같이 cross_val_predict() 함수를 통한 예측
- confusion_matrix() 함수 호출
y_train_pred = cross_val_predict(sgd_clf, X_train_scaled, y_train, cv=3)
conf_mx = confusion_matrix(y_train, y_train_pred)
conf_mx
>> array([[5577, 0, 22, 5, 8, 43, 36, 6, 225, 1],
[ 0, 6400, 37, 24, 4, 44, 4, 7, 212, 10],
[ 27, 27, 5220, 92, 73, 27, 67, 36, 378, 11],
[ 22, 17, 117, 5227, 2, 203, 27, 40, 403, 73],
[ 12, 14, 41, 9, 5182, 12, 34, 27, 347, 164],
[ 27, 15, 30, 168, 53, 4444, 75, 14, 535, 60],
[ 30, 15, 42, 3, 44, 97, 5552, 3, 131, 1],
[ 21, 10, 51, 30, 49, 12, 3, 5684, 195, 210],
[ 17, 63, 48, 86, 3, 126, 25, 10, 5429, 44],
[ 25, 18, 30, 64, 118, 36, 1, 179, 371, 5107]])
- 이미지를 통해 오차 행렬 확인
def plot_confusion_matrix(matrix):
"""If you prefer color and a colorbar"""
fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot(111)
cax = ax.matshow(matrix)
fig.colorbar(cax)
- 대부분의 이미지가 올바르게 분류 되었음을 확인 가능
- 에러 부분에만 초점을 맞추기 위해 오차 행렬의 각 값에 대응되는 클래스의 이미지 개수로 나눠서 에러 비율을 비교
- 이미지가 많은 클래스가 상대적으로 안좋게 시각화
row_sums = conf_mx.sum(axis=1, keepdims=True)
norm_conf_mx = conf_mx / row_sums
# 다른 항목 유지 + 주대각선만 0으로 채워서 그래프 시각화
np.fill_diagonal(norm_conf_mx, 0)
plt.matshow(norm_conf_mx, cmap=plt.cm.gray)
plt.show()
행은 실제 클래스를 의미, 열은 예측한 클래스를 나타냄
- 8번 그림을 보면 raw 인 실제 클래스 8로는 예측이 잘 수행되었지만, col 인 예측 클래스 8은 좋지 않음으로 많은 이미지가 class 8로 잘못 분류되었음
- 이를 통해서 8로 잘못 분류되는 문제를 줄이도록 개선해야하는 필요성이 커짐
- 추가적인 8관련 이미지를 더 추가, 8 이미지에 대한 특성 추가
cl_a, cl_b = 3, 5
X_aa = X_train[(y_train == cl_a) & (y_train_pred == cl_a)]
X_ab = X_train[(y_train == cl_a) & (y_train_pred == cl_b)]
X_ba = X_train[(y_train == cl_b) & (y_train_pred == cl_a)]
X_bb = X_train[(y_train == cl_b) & (y_train_pred == cl_b)]
plt.figure(figsize=(8,8))
plt.subplot(221); plot_digits(X_aa[:25], images_per_row=5)
plt.subplot(222); plot_digits(X_ab[:25], images_per_row=5)
plt.subplot(223); plot_digits(X_ba[:25], images_per_row=5)
plt.subplot(224); plot_digits(X_bb[:25], images_per_row=5)
save_fig("error_analysis_digits_plot")
plt.show()
- 왼쪽 5x5 두개는 3으로 분류된 이미지, 오른쪽 5x5는 5로 분류된 이미지
- 가장큰 원인은 선형 모델인 SGDClassifier를 사용했기 때문, 선형 분류기는 클래스마다 픽셀에 가중치를 할당하고 새로운 이미지에 대해 단순히 픽셀 강도의 가중치 합을 클래스 점수로 계산
다중 레이블 분류
- 여러 개의 이진 라벨을 출력하는 분류 시스템을 다중 레이블 분류
- KNeighborsClassifier은 다중 레이블 분류를 지원
- 예측을 수행시 레이블 두 개가 출력
from sklearn.neighbors import KNeighborsClassifier
y_train_large = (y_train >= 7)
y_train_odd = (y_train % 2 == 1)
y_multilabel = np.c_[y_train_large, y_train_odd]
knn_clf = KNeighborsClassifier()
knn_clf.fit(X_train, y_multilabel)
knn_clf.predict([some_digit])
>> array([[False, True]]) # 7이상이 아니고 홀수
- 모든 레이블에 대한 f1 score 계산
- 모든 가중치가 동일하다고 보고 계산하는것, 일부 사진이 더 많다면 클래스의 지지도(target label에 속한 sample 수)를 가중치로 주는 것 -> average="weighted"로 설정
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")
다중 출력 분류
- 다중 레이블 분류에서 한 레이블이 다중 클래스가 될수 있도록 일반화 한 것(즉, 값 두 개 이상 가질수 있음)
- 이미지에서 잡음을 제거하는 시스템을 예시로 수행
# randint()를 통해 잡음추가
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
# 시각화
some_index = 0
plt.subplot(121); plot_digit(X_test_mod[some_index])
plt.subplot(122); plot_digit(y_test_mod[some_index])
plt.show()
- 분류기를 통해 잡음 제거 이미지 분류기 생성
knn_clf.fit(X_train_mod, y_train_mod)
clean_digit = knn_clf.predict([X_test_mod[some_index]])
plot_digit(clean_digit)
x 가 잡음이 있는 이미지, y가 잡음없는 이미지 인 상태로 훈련
결과적으로 잡음 없는 이미지가 선택
연습문제
1.97% 정확도의 MNIST 분류기
from sklearn.model_selection import GridSearchCV
param_grid = [{'weights': ["uniform", "distance"], 'n_neighbors': [3, 4, 5]}]
knn_clf = KNeighborsClassifier()
grid_search = GridSearchCV(knn_clf, param_grid, cv=5, verbose=3)
grid_search.fit(X_train, y_train)
grid_search.best_params_
>> {'n_neighbors': 4, 'weights': 'distance'}
grid_search.best_score_
>> 0.97
from sklearn.metrics import accuracy_score
y_pred = grid_search.predict(X_test)
accuracy_score(y_test, y_pred)
>> 0.9714
2.데이터 증식
from scipy.ndimage.interpolation import shift
def shift_image(image, dx, dy):
image = image.reshape((28, 28))
shifted_image = shift(image, [dy, dx], cval=0, mode="constant")
return shifted_image.reshape([-1])
image = X_train[1000]
shifted_image_down = shift_image(image, 0, 5)
shifted_image_left = shift_image(image, -5, 0)
plt.figure(figsize=(12,3))
plt.subplot(131)
plt.title("Original", fontsize=14)
plt.imshow(image.reshape(28, 28), interpolation="nearest", cmap="Greys")
plt.subplot(132)
plt.title("Shifted down", fontsize=14)
plt.imshow(shifted_image_down.reshape(28, 28), interpolation="nearest", cmap="Greys")
plt.subplot(133)
plt.title("Shifted left", fontsize=14)
plt.imshow(shifted_image_left.reshape(28, 28), interpolation="nearest", cmap="Greys")
plt.show()
# 증분
X_train_augmented = [image for image in X_train]
y_train_augmented = [label for label in y_train]
for dx, dy in ((1, 0), (-1, 0), (0, 1), (0, -1)):
for image, label in zip(X_train, y_train):
X_train_augmented.append(shift_image(image, dx, dy))
y_train_augmented.append(label)
X_train_augmented = np.array(X_train_augmented)
y_train_augmented = np.array(y_train_augmented)
# 셔플
shuffle_idx = np.random.permutation(len(X_train_augmented))
X_train_augmented = X_train_augmented[shuffle_idx]
y_train_augmented = y_train_augmented[shuffle_idx]
knn_clf = KNeighborsClassifier(**grid_search.best_params_)
knn_clf.fit(X_train_augmented, y_train_augmented)
y_pred = knn_clf.predict(X_test)
accuracy_score(y_test, y_pred)
>> 0.9763
3.타이타닉 데이터셋
- 승객의 나이, 성별, 승객 등급, 승선 위치 같은 속성을 기반으로 하여 승객의 생존 여부를 예측하는 것이 목표
- 데이터 다운 & 로드
import os
import urllib.request
TITANIC_PATH = os.path.join("datasets", "titanic")
DOWNLOAD_URL = "https://raw.githubusercontent.com/rickiepark/handson-ml2/master/datasets/titanic/"
# 데이터 다운
def fetch_titanic_data(url=DOWNLOAD_URL, path=TITANIC_PATH):
if not os.path.isdir(path):
os.makedirs(path)
for filename in ("train.csv", "test.csv"):
filepath = os.path.join(path, filename)
if not os.path.isfile(filepath):
print("Downloading", filename)
urllib.request.urlretrieve(url + filename, filepath)
fetch_titanic_data()
# 데이터 불러오기
import pandas as pd
def load_titanic_data(filename, titanic_path=TITANIC_PATH):
csv_path = os.path.join(titanic_path, filename)
return pd.read_csv(csv_path)
train_data = load_titanic_data("train.csv")
test_data = load_titanic_data("test.csv")
- 데이터 열 설명 및 확인
- PassengerId: 각 승객의 고유 식별자.
- Survived: 타깃입니다. 0은 생존하지 못한 것이고 1은 생존을 의미합니다.
- Pclass: 승객 등급. 1, 2, 3등석.
- Name, Sex, Age: 이름 그대로 의미입니다.
- SibSp: 함께 탑승한 형제, 배우자의 수.
- Parch: 함께 탑승한 자녀, 부모의 수.
- Ticket: 티켓 아이디
- Fare: 티켓 요금 (파운드)
- Cabin: 객실 번호
- Embarked: 승객이 탑승한 곳. C(Cherbourg), Q(Queenstown), S(Southampton)
- PassengerId 열을 인덱스 열로 지정
train_data = train_data.set_index("PassengerId")
test_data = test_data.set_index("PassengerId")
- 누락 및 통계치 확인
- null 은 없고 전체 38% 정도가 생존, 평균 Fare은 32.20 , 평균 나이는 30보다 적음
- 타겟및 범주형 데이터 확인
# 0,1로 이루어진 target
train_data["Survived"].value_counts()
>> 0 549
1 342
# 범주형 데이터 확인
train_data["Pclass"].value_counts() # 승객 등급
>> 3 491
1 216
2 184
train_data["Sex"].value_counts() # 성별
>> male 577
female 314
train_data["Embarked"].value_counts() # 탑승한 곳 C=Cherbourg, Q=Queenstown, S=Southampton.
>> S 644
C 168
Q 77
- 수치 특성을 처리하기 위한 파이프라인
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import OneHotEncoder
num_pipeline = Pipeline([
("imputer", SimpleImputer(strategy="median")),
("scaler", StandardScaler())
])
# nan을 중앙값으로 변환후 standardscaler 적용
- 범주형 특성 처리를 위한 파이프라인
cat_pipeline = Pipeline([
("imputer", SimpleImputer(strategy="most_frequent")),
("cat_encoder", OneHotEncoder(sparse=False)),
])
# nan을 최빈값으로 설정후 OneHotEncoder를 통해 수치형으로 변환
- 열별 다른 전처리 기법 사용 (범주형은 범주로, 수치형은 수치로)
from sklearn.compose import ColumnTransformer
num_attribs = ["Age", "SibSp", "Parch", "Fare"]
cat_attribs = ["Pclass", "Sex", "Embarked"]
preprocess_pipeline = ColumnTransformer([
("num", num_pipeline, num_attribs),
("cat", cat_pipeline, cat_attribs),
])
# ColumnTransformer를 통해서 열별로 다른 전처리 방법 사용
# 최종 전처리 결과
X_train = preprocess_pipeline.fit_transform(train_data[num_attribs + cat_attribs])
X_train
>> array([[-0.56573646, 0.43279337, -0.47367361, ..., 0. ,
0. , 1. ],
[ 0.66386103, 0.43279337, -0.47367361, ..., 1. ,
0. , 0. ],
[-0.25833709, -0.4745452 , -0.47367361, ..., 0. ,
0. , 1. ],
...,
[-0.1046374 , 0.43279337, 2.00893337, ..., 0. ,
0. , 1. ],
[-0.25833709, -0.4745452 , -0.47367361, ..., 1. ,
0. , 0. ],
[ 0.20276197, -0.4745452 , -0.47367361, ..., 0. ,
1. , 0. ]])
# target
y_train = train_data["Survived"]
- RandomForestClassifier 를 통한 학습
from sklearn.ensemble import RandomForestClassifier
forest_clf = RandomForestClassifier(n_estimators=100, random_state=42)
forest_clf.fit(X_train, y_train)
# 예측
X_test = preprocess_pipeline.transform(test_data[num_attribs + cat_attribs])
y_pred = forest_clf.predict(X_test)
# 성능평가
from sklearn.model_selection import cross_val_score
forest_scores = cross_val_score(forest_clf, X_train, y_train, cv=10)
forest_scores.mean()
>> 0.809
from sklearn.svm import SVC
svm_clf = SVC(gamma="auto")
svm_scores = cross_val_score(svm_clf, X_train, y_train, cv=10)
svm_scores.mean()
>> 0.824
- 두 모델 사이의 성능 시각화 to boxplot()
- 1사분위가 Q1이고 3사분위가 Q3이라면 사분위수 범위는 IQR=Q3−Q1(박스의 높이)
- Q1−1.5×IQR 보다 낮거나 Q3+1.5×IQR 보다 높은 점수는 이상치로 간주
import matplotlib.pyplot as plt
plt.figure(figsize=(8, 4))
plt.plot([1]*10, svm_scores, ".")
plt.plot([2]*10, forest_scores, ".")
plt.boxplot([svm_scores, forest_scores], labels=("SVM","Random Forest"))
plt.ylabel("Accuracy", fontsize=14)
plt.show()
추가적인 전처리 방법으로는 그리드 탐색, 모델비교, 범주형을 구간으로 변경
반응형
'Study > Self Education' 카테고리의 다른 글
핸즈온 머신러닝 - 6 (0) | 2024.06.18 |
---|---|
핸즈온 머신러닝 - 5 (0) | 2024.06.17 |
핸즈온 머신러닝 - 4 (2) | 2024.06.17 |
핸즈온 머신러닝 - 2 (0) | 2024.06.13 |
핸즈온 머신러닝 - 1 (1) | 2024.06.13 |