7.Random Forest Code
[목적]
- Decision Tree 실습 및 해석
- Variance를 낮추기위한 Bagging의 대표적인 모델 RandomForest 실습 및 해석
[Process]
- Define X’s & Y
- Split Train & Valid dataset
- Modeling
- 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]
- 오른 쪽이 T이고 왼쪽이 F임
- event>901이면 gini가 0.058이고, 무려 193이 dead로 판단 됨: 얘는 뒤에 더 안봐도 될듯
- gini = 0일 때 full tree, 완전 분류가 된거 임, 근데 depth가 높을 때는 별로 유용한 정보는 아님
- 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()
- feature importance score를 시각화 해준 것 elbow point: cd 496으로 잡고 3개 deciscion tree돌려봄
댓글남기기