개발/💠 Alchemist
💠 분류 - 캐글 산탄데르 고객 만족 예측 💠
정소은
2023. 10. 31. 18:37
< 캐글 산탄데르 고객 만족 예측 >

1. 데이터세트 로딩 및 데이터 세트 전처리
패키지, dataset import
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
import warnings
warnings.filterwarnings('ignore')
cust_df = pd.read_csv('/Users/jeongsoeun/Downloads/train.csv', encoding='latin-1')
# 데이터세트 행렬 파악 : (76020, 371)
print('dataset shape:', cust_df.shape)
# 데이터세트 3줄 출력
cust_df.head(3)
dataset 정보 파악 - feature 371개 존재
cust_df.info()

피처의 레이블 정보 파악
print(cust_df['TARGET'].value_counts())
unsatisfied_cnt = cust_df[cust_df['TARGET']==1].TARGET.count()
total_cnt = cust_df.TARGET.count()
print('unsatisfied 비율은 {0:.2f}'.format((unsatisfied_cnt / total_cnt)))

모두 숫자형이며 float형 111개, int형 260개, Null값은 없음
'Target' 칼럼 - 대부분이 만족이고 불만족이 4%에 불과한 불균형한 레이블값을 가짐
피처값의 분포 확인
cust_df.describe()

'var3' 칼럼 - min값이 -999999 / -999999 값이 116개 존재 (다른 값에 비해 편차가 심하기 때문에 모델 성능에 나쁜 영향을 줌)
dataset 조정
# -999999값을 가장 값이 많은 2로 변환
cust_df['var3'].replace(-999999,2,inplace=True)
# 무의미한 'ID' 칼럼 drop
cust_df.drop('ID', axis=1, inplace=True)
# 피처 세트와 레이블 세트 분리
X_features = cust_df.iloc[:, :-1]
y_labels = cust_df.iloc[:, -1]
print('피처 데이터 shape:{0}'.format(X_features.shape))

2. 학습 / 테스트 데이터 분리
학습 / 테스트 데이터 분리
from sklearn.model_selection import train_test_split
# 학습/테스트 데이터 분리
X_train, X_test, y_train, y_test = train_test_split(X_features, y_labels, test_size=0.2, random_state=0)
# 학습/테스트 데이터의 Target의 학습/테스트 세트 레이블값 분포 확인
train_cnt = y_train.count()
test_cnt = y_test.count()
print('학습 세트 Shape:{0}, 테스트 세트 Shape:{1}'.format(X_train.shape, X_test.shape))
print('학습 세트 레이블 값 분포 비율')
print(y_train.value_counts()/train_cnt)
print('\n테스트 세트 레이블 값 분포 비율')
print(y_test.value_counts()/test_cnt)

학습 세트 - 학습 / 검증 세트로 분리
X_tr, X_val, y_tr, y_val = train_test_split(X_train, y_train, test_size = 0.3, random_state = 0)
< XGBClassifier 이용 >
3. XGBClassifier의 하이퍼 파라미터 튜닝
XGBoost 모델 학습과 하이퍼 파라미터 튜닝
from xgboost import XGBClassifier
from sklearn.metrics import roc_auc_score
# XGBClassifier 객체 생성
xgb_clf = XGBClassifier(n_estimators=500, learning_rate=0.05, random_state=156)
# XGBClassifier 모델 학습
xgb_clf.fit(X_tr, y_tr, early_stopping_rounds=100, eval_metric="auc", eval_set=[(X_tr, y_tr),(X_val, y_val)])
# XGBClassifier 성능 평가 - ROC AUC -> 결과 : 0.8429
xgb_roc_score = roc_auc_score(y_test, xgb_clf.predict_proba(X_test)[:,-1])
print('ROC AUC: {0:.4f}'.format(xgb_roc_score))
XGBoost 하이퍼 파라미터 튜닝 - HyperOpt
from hyperopt import hp
## 검색 공간 설정 ##
# max_depth는 5~15까지 1 간격으로, min_child_weight는 1~6까지 1 간격으로
# colsample_bytree는 0.5~0.95 사이, learning_rate는 0.01~2 사이 정규 분포된 값으로 검색공간 설정
xgb_search_space = {'max_depth':hp.quniform('max_depth',5,15,1),
'min_child_weight':hp.quniform('min_child_weight',1,6,1),
'colsample_bytree':hp.uniform('colsample_bytree',0.5,0.95),
'learning_rate':hp.uniform('learning_rate',0.01,0.2)}
## 목적 함수 생성 ##
from sklearn.model_selection import KFold
from sklearn.metrics import roc_auc_score
# fmin()에서 호출 시 search_space 값으로 XGBClassifier 교차 검증 학습 후 -1*roc_auc 평균 값 반환
def objective_func(search_space):
# XGBoost 객체 생성
xgb_clf = XGBClassifier(n_estimators = 100, max_depth = int(search_space['max_depth']),
min_child_weight = int(search_space['min_child_weight']),
colsample_bytree = search_space['colsample_bytree'],
learning_rate = search_space['learning_rate'])
# 3개 k-fold 방식으로 평가된 roc_auc 지표를 담는 list
roc_auc_list = []
# 3개 k-fold 방식 적용
kf = KFold(n_splits=3)
# X_train을 다시 학습과 검증용 데이터로 분리
for tr_index, val_index in kf.split(X_train):
X_tr, y_tr = X_train.iloc[tr_index], y_train.iloc[tr_index]
X_val, y_val = X_train.iloc[val_index], y_train.iloc[val_index]
# early stopping은 30회로 설정하고 추출된 학습과 검증 데이터로 XGBClassifier 학습 수행
xgb_clf.fit(X_tr, y_tr, early_stopping_rounds=30, eval_metric="auc",
eval_set = [(X_tr, y_tr),(X_val, y_val)])
# 1로 예측한 확률값 추출 후 roc auc 계산을 위해 list에 결괏값 담음
score = roc_auc_score(y_val, xgb_clf.predict_proba(X_val)[:, 1])
roc_auc_list.append(score)
# 3개 k-fold로 계산된 roc_auc 값의 평균값을 반환하되
# HyperOpt는 목적함수의 최솟값을 위한 입력값을 찾으므로 -1 곱한 뒤 반환
return -1*np.mean(roc_auc_list)
## 최적 하이퍼 파라미터 도출 ##
from hyperopt import fmin, tpe, Trials
trials = Trials()
# fmin() 함수 호출, max_evals 지정된 횟수(50)만큼 반복 후 목적함수의 최솟값을 가지는 최적 입력값 추출
best = fmin(fn=objective_func,
space=xgb_search_space,
algo=tpe.suggest,
max_evals=50,
trials=trials, rstate=np.random.default_rng(seed=30))
print('best:',best)
결과 - colsample_bytree : 0.5749, learning_rate : 0.1514, max_depth : 5.0, min_child_weight : 6.0
4. XGBClassifier 적용
최적 하이퍼 파라미터 값으로 XGBClassifier 재학습
# XGBClassifier 객체 생성
xgb_clf = XGBClassifier(n_estimators=500, learning_rate=round(best['learning_rate'], 5),
max_depth=int(best['max_depth']),
min_child_weight=int(best['min_child_weight']),
colsample_bytree=round(best['colsample_bytree'], 5))
# 모델 학습
xgb_clf.fit(X_tr, y_tr, early_stopping_rounds=100,
eval_metric="auc", eval_set=[(X_tr, y_tr),(X_val, y_val)])
# 모델 예측 성능 평가
xgb_roc_score=roc_auc_score(y_test, xgb_clf.predict_proba(X_test)[:,1])
print('ROC AUC: {0:.4f}'.format(xgb_roc_score))
결과 - ROC AUC 값 : 0.8457 ( 하이퍼 파라미터 튜닝 전보다 성능 상승 )
feature 중요도 그래프
from xgboost import plot_importance
import matplotlib.pyplot as plt
%matplotlib inline
fig, ax = plt.subplots(1,1,figsize=(10,8))
plot_importance(xgb_clf, ax=ax, max_num_features=20, height=0.4)
< Light GBM 이용 >
4. LGBMClassifier
LGBMClassifier 학습과 하이퍼 파라미터 튜닝
from lightgbm import LGBMClassifier
# LGBMClassifier 객체 생성
lgbm_clf = LGBMClassifier(n_estimators=500)
# 학습/검증 데이터세트
eval_set = [(X_tr, y_tr),(X_val, y_val)]
# 모델 학습
lgbm_clf.fit(X_tr, y_tr, early_stopping_rounds=100, eval_metric="auc", eval_set = eval_set)
# 모델 성능 평가 - roc_auc
lgbm_roc_score = roc_auc_score(y_test, lgbm_clf.predict_proba(X_test)[:,1])
print('ROC AUC: {0:.4f}'.format(lgbm_roc_score))
5. LGBMClassifier 하이퍼 파라미터 튜닝 - HyperOpt
# LGBMClassifier 검색 공간 설정
lgbm_search_space = {'num_leaves':hp.quniform('num_leaves',32,64,1),
'max_depth':hp.quniform('max_depth',100,160,1),
'min_child_samples':hp.quniform('min_child_samples',60,100,1),
'subsample':hp.uniform('subsample', 0.7, 1),
'learning_rate':hp.uniform('learning_rate',0.01, 0.2)}
# 목적 함수 생성
def objective_func(search_space):
lgbm_clf = LGBMClassifier(n_estimator=100,
num_leaves=int(search_space['num_leaves']),
max_depth=int(search_space['max_depth']),
min_child_samples=int(search_space['min_child_samples']),
subsample=search_space['subsample'],
learning_rate= search_space['learning_rate'])
roc_auc_list = []
kf = KFold(n_splits=3)
for tr_index, val_index in kf.split(X_train):
X_tr, y_tr = X_train.iloc[tr_index], y_train.iloc[tr_index]
X_val, y_val = X_train.iloc[val_index], y_train.iloc[val_index]
lgbm_clf.fit(X_tr, y_tr, early_stopping_rounds = 30, eval_metric = "auc",
eval_set = [(X_tr, y_tr),(X_val, y_val)])
score = roc_auc_score(y_val, lgbm_clf.predict_proba(X_val)[:, 1])
roc_auc_list.append(score)
return -1*np.mean(roc_auc_list)
# 최적 하이퍼 파라미터 도출
from hyperopt import fmin, tpe, Trials
trials = Trials()
best = fmin(fn=objective_func, space=lgbm_search_space, algo=tpe.suggest, max_evals=50, trials=trials, rstate=np.random.default_rng(seed=30))
print('best:',best)
결괏값 - learning_rate : 0.08592, max_depth : 121.0, min_child_samples : 69.0, num_leaves : 41.0, subsample : 0.91489
5. LGBMClassifier 적용
LGBMClassifier 적용
lgbm_clf = LGBMClassifier(n_estimators=500, num_leaves=int(best['num_leaves']),
max_depth=int(best['max_depth']),
min_child_samples=int(best['min_child_samples']),
subsample=round(best['subsample'], 5),
learning_rate=round(best['learning_rate'],5))
lgbm_clf.fit(X_tr, y_tr, early_stopping_rounds=100,
eval_metric="auc", eval_set=[(X_tr, y_tr),(X_val, y_val)])
lgbm_roc_score = roc_auc_score(y_test, xgb_clf.predict_proba(X_test)[:,1])
print('ROC AUC: {0:.4f}'.format(lgbm_roc_score))