4 분 소요

[목적]

  1. Decision Tree 실습 및 해석
  2. Variance를 낮추기위한 Bagging의 대표적인 모델 RandomForest 실습 및 해석

[Process]

  1. Define X’s & Y
  2. Split Train & Valid dataset
  3. Modeling
  4. Model 해석
import os
import gc
import pickle
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

import warnings
warnings.filterwarnings("ignore")

from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, f1_score
from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor
from sklearn.tree import DecisionTreeClassifier, export_graphviz
from collections import Counter
from sklearn import tree
  • 함수 호출: seaborn->시각화 쓰는 듯 f1 score: acc를 못 씀-> imblance있는듯
# Data Loading (수술 時 사망 데이터)
data = pd.read_csv("https://raw.githubusercontent.com/GonieAhn/Data-Science-online-course-from-gonie/main/Data%20Store/example_data.csv")
  • censor=1이면 살린 것, =0이면 dead
data.shape
  • 532개 행 23개 열, 항상 shape은 확인
  • tree 계열은 scaling 필요 없음^ㅇ^
# Label Balace Check - Imbalance
Counter(data['censor'])
  • censor를 y로 잡을 껀데, imblance가 있네-> f1쓰자
# X's & Y Split
Y = data['censor']
X = data.drop(columns=['censor'])
  • x는 censor 뺀거, y는 censor만
idx = list(range(X.shape[0]))
train_idx, valid_idx = train_test_split(idx, test_size=0.3, random_state=2023)
print(">>>> # of Train data : {}".format(len(train_idx)))
print(">>>> # of valid data : {}".format(len(valid_idx)))
print(">>>> # of Train data Y : {}".format(Counter(Y.iloc[train_idx])))
print(">>>> # of valid data Y : {}".format(Counter(Y.iloc[valid_idx])))
  • 인덱스 지정: test 사이즈 0.3지정 train: 372개, test: 160개 counter: train,test 각각의 0,1의 개수 반환 iloc쓸 수 있는게 아마 idx가 int로 반환되어서 그런 듯
# Depth 조절 Decision Tree
for i in range(2,11,1):
    print(">>>> Depth {}".format(i))

    model = DecisionTreeClassifier(max_depth=i, criterion='gini')
    model.fit(X.iloc[train_idx], Y.iloc[train_idx])

    # Train Acc
    y_pre_train = model.predict(X.iloc[train_idx])
    cm_train = confusion_matrix(Y.iloc[train_idx], y_pre_train)
    print("Train Confusion Matrix")
    print(cm_train)
    print("Train Acc : {}".format((cm_train[0,0] + cm_train[1,1])/cm_train.sum()))
    print("Train F1-Score : {}".format(f1_score(Y.iloc[train_idx], y_pre_train)))

    # Test Acc
    y_pre_test = model.predict(X.iloc[valid_idx])
    cm_test = confusion_matrix(Y.iloc[valid_idx], y_pre_test)
    print("Train Confusion Matrix")
    print(cm_test)
    print("TesT Acc : {}".format((cm_test[0,0] + cm_test[1,1])/cm_test.sum()))
    print("Test F1-Score : {}".format(f1_score(Y.iloc[valid_idx], y_pre_test)))
    print("-----------------------------------------------------------------------")
    print("-----------------------------------------------------------------------")
  • 일단 max depth를 10으로 지정함-> 나중에 최적의 depth는 f1 score 가지고 따질 듯
  • gini index를 기준으로 분류하는 듯
  • 근데 보니까 acc도 일단 같이 따지는 듯? -> 그래도 f1 score 보셈
model = DecisionTreeClassifier(max_depth=4, criterion='gini')
model.fit(X.iloc[train_idx], Y.iloc[train_idx])
  • depth 4->5 갈 때 f1 떨어짐-> best depth:4
# Creating the tree plot
tree.plot_tree(model, filled=True, feature_names=X.columns, class_names = ['Dead', 'indicator'])
plt.rcParams['figure.figsize'] = [30,10]

image

  • 오른 쪽이 T이고 왼쪽이 F임
    1. event>901이면 gini가 0.058이고, 무려 193이 dead로 판단 됨: 얘는 뒤에 더 안봐도 될듯
    2. gini = 0일 때 full tree, 완전 분류가 된거 임, 근데 depth가 높을 때는 별로 유용한 정보는 아님
    3. cd496 <= 161.5일 때 gini=0 도출 가능 이거는 꽤 유용함 결론 : event>901: dead의 위험 높음, cd496 <= 161.5: 거의 확실하게 살 수 있음

[Random Forest]

  • Hyperparameter tuning
  • estimators, depth
  • Random Forest는 이 두개만 조절해도 좋은 결과를 얻을 수 있음
  • GridSearchCV를 사용하지 않고 For Loop를 돌리는 이유
    • 내가 원하는 결과를 저장하고 Display 하고 싶음
    • 내가 원하는 결과를 실시간 Display 하면서 그때 그때 파라미터 튜닝에 대한 대처를 하고 싶음
  • 사용하는 파라미터:
    • n_estimators : 몇 개의 트리를 만들 것 인지
    • criterion : 스플릿 할 때 기준
      • Gini
      • entropy
      • log_loss
    • max_depth : Tree의 최대 깊이 제한
    • min_samples_split : 2개로 Split 하는게 아니라 N개로 Split 가능
    • bootstrap : Bagging 중 Bootstrap 기법-> 첫번째 chosen
    • max_features : Feature 수 sampling -> **두번째 chosen **
      • auto
      • sqrt
      • log2
    • oob_score : out-of-bag Score, 한번도 추출 안된 친구들
    • class_weight : Label Imbalance 데이터 학습시 weight를 주는 것-> 적은 쪽에 weight를 줌
      • {0: 1, 1: 1}
    • random_state : Two way Random Choosen 때문에 매 결과가 달라짐
      • 지정한 값으로 해주는 것이 결과가 같아짐
# RandomForest Hyperparameter
estimators = [10, 30, 40, 50, 60]
depth = [4 , 5, 10, 15]

# Modeling
save_est = []
save_dep = []
f1_score_ = []

cnt = 0
for est in estimators:
    for dep in depth:
        print(">>> {} <<<".format(cnt))
        cnt += 1
        print("Number of Estimators : {}, Max Depth : {}".format(est, dep))

        model = RandomForestClassifier(n_estimators=est, max_depth=dep,random_state=119,
                                       criterion='gini', max_features='auto',
                                       bootstrap=True, oob_score=False) # if you use "oob_score=True", get long time for training
        model.fit(X.iloc[train_idx], Y.iloc[train_idx])

        # Train Acc
        y_pre_train = model.predict(X.iloc[train_idx])
        cm_train = confusion_matrix(Y.iloc[train_idx], y_pre_train)
        print("Train Confusion Matrix")
        print(cm_train)
        print("Train Acc : {}".format((cm_train[0,0] + cm_train[1,1])/cm_train.sum()))
        print("Train F1-Score : {}".format(f1_score(Y.iloc[train_idx], y_pre_train)))

        # Test Acc
        y_pre_test = model.predict(X.iloc[valid_idx])
        cm_test = confusion_matrix(Y.iloc[valid_idx], y_pre_test)
        print("Test Confusion Matrix")
        print(cm_test)
        print("TesT Acc : {}".format((cm_test[0,0] + cm_test[1,1])/cm_test.sum()))
        print("Test F1-Score : {}".format(f1_score(Y.iloc[valid_idx], y_pre_test)))
        print("-----------------------------------------------------------------------")
        print("-----------------------------------------------------------------------")
        save_est.append(est)
        save_dep.append(dep)
        f1_score_.append(f1_score(Y.iloc[valid_idx], y_pre_test))
  • est, dep, f1_score들을 저장함
  • OOB를 True로 두면 시간이 좀 더 걸림: 런타임 에러 날 수도
  • model.predict(X.iloc[train_idx]): 이거는 x의 train_idx를 입력 받아 모델이 예측을 수행 즉 학습
# Best Model
best_model = RandomForestClassifier(n_estimators=save_est[np.argmax(f1_score_)], max_depth=save_dep[np.argmax(f1_score_)], random_state=119,
                               criterion='gini', max_features='auto',
                               bootstrap=True, oob_score=False) # if you use "oob_score=True", get long time for training
best_model.fit(X.iloc[train_idx], Y.iloc[train_idx])
  • f1 score가 가장 큰 model을 가져와줘: argmax(f1score)
  • max_depth=15, n_estimators=50 가 제일 베스트 모델
# Train Acc
y_pre_train = best_model.predict(X.iloc[train_idx])
cm_train = confusion_matrix(Y.iloc[train_idx], y_pre_train)
print("Train Confusion Matrix")
print(cm_train)
print("Train Acc : {}".format((cm_train[0,0] + cm_train[1,1])/cm_train.sum()))
print("Train F1-Score : {}".format(f1_score(Y.iloc[train_idx], y_pre_train)))

# Test Acc
y_pre_test = best_model.predict(X.iloc[valid_idx])
cm_test = confusion_matrix(Y.iloc[valid_idx], y_pre_test)
print("Test Confusion Matrix")
print(cm_test)
print("TesT Acc : {}".format((cm_test[0,0] + cm_test[1,1])/cm_test.sum()))
print("Test F1-Score : {}".format(f1_score(Y.iloc[valid_idx], y_pre_test)))
  • best모델로 학습
feature_map = pd.DataFrame(sorted(zip(best_model.feature_importances_, X.columns), reverse=True), columns=['Score', 'Feature'])
print(feature_map)
  • feature importance score 구하기
    event, cd420등이 중요한 feature로 선정
# Importance Score Top 10
feature_map_20 = feature_map.iloc[:10]
plt.figure(figsize=(20, 10))
sns.barplot(x="Score", y="Feature", data=feature_map_20.sort_values(by="Score", ascending=False), errwidth=40)
plt.title('Random Forest Importance Features')
plt.tight_layout()
plt.show()

image

  • feature importance score를 시각화 해준 것 elbow point: cd 496으로 잡고 3개 deciscion tree돌려봄

카테고리:

업데이트:

댓글남기기