본문 바로가기

파이썬 머신러닝 완벽가이드

4.6 산타데르 은행 고객 만족도 데이터셋 실습

728x90

지금까지 배운 XGboost, LightGBM을 이용하여 

산타데르 은행 고객 만족도 데이터셋 분석을 해보도록 하겠습니다.

 

해당 내용은 '파이썬 머신러닝 완벽 가이드'를 정리한 내용입니다.


import numpy as np 
import pandas as pd 
import matplotlib.pyplot as plt
import matplotlib

cust_df = pd.read_csv("./train_santander.csv",encoding='latin-1')
cust_df.info()

 

먼저 '산타데르 은행 고객 만족도 데이터셋의 속성을 살펴보겠습니다. 총 371개의 속성으로 이루어져 있으며 가장 마지막 행은 'Target'으로 1이면 불만족, 0이면 만족을 의미합니다.

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 76020 entries, 0 to 76019
Columns: 371 entries, ID to TARGET
dtypes: float64(111), int64(260)
memory usage: 215.2 MB

 

이진 분류 모델에서는 데이터의 분포도를 살펴보는 것은 매우 중요합니다. 불균형한 데이터셋일 확률이 매우 높기 때문이죠.

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)))

 

0    73012
1     3008
Name: TARGET, dtype: int64
unsatisfied 비율은 0.04

불만족일 확률이 4%로 생각보다 높네요... 아주 정직한 데이터셋인 것 같습니다ㅋㅋㅋ

 

다음은 각 속성의 값들의 특징을 살펴보도록 하겠습니다.

cust_df.describe( )

 

 

데이터의 속성이 371개나 되기 때문에 각각의 속성을 일일이 확인하기보다는 '-99999999'로 가장 눈에 띄는 값이 있는 var3에 대해서만 데이터 전처리를 하도록 하겠습니다. 먼저 var3에 있는 값들의 수 살펴보도록 하겠습니다.

print(cust_df['var3'].value_counts( )[:10])

 

 2         74165
 8           138
-999999      116
 9           110
 3           108
 1           105
 13           98
 7            97
 4            86
 12           85
Name: var3, dtype: int64

 

위의 결과를 보면 알 수 있듯이 해당 데이터 셋은 예외값을 -99999로 표현한 것 같습니다. 하지만 이는 다른 값과 너무 큰 편차가 나기 때문에 가장 많은 2로 변환하겠습니다. 이후 필요 없는 속성인 'ID'는 삭제하고 데이터와 라벨을 분리하도록 하겠습니다.

 

# var3 피처 값 대체 및 ID 피처 드롭
cust_df['var3'].replace(-999999, 2, inplace=True)
cust_df.drop('ID',axis=1 , inplace=True)

# 피처 세트와 레이블 세트분리. 레이블 컬럼은 DataFrame의 맨 마지막에 위치해 컬럼 위치 -1로 분리
X_features = cust_df.iloc[:, :-1]
y_labels = cust_df.iloc[:, -1]
print('피처 데이터 shape:{0}'.format(X_features.shape))

 

피처 데이터 shape:(76020, 369)

 

데이터 준비가 끝났으니 이제 학습 데이터와 테스트 데이터를 분리하겠습니다. 데이터를 분리할 때 중요한건 원래 데이터의 분포를 학습 데이터와 테스트 데이터가 유지해야 한다는 점입니다. 원래 데이터의 불만족 비율이 4%에 불가한데 학습 데이터에서는 30%라면 이는 제대로 된 정보를 학습하는 것이 아니겠죠? 

따라서 데이터의 분포도를 유지해주는 것은 매우 중요한데 이를 가능하게 해주는 속성이 바로 stratify 입니다. 해당 속성을 사용하여 y_labels의 분포에 따라 데이터를 분리하도록 하겠습니다.

from sklearn.model_selection import train_test_split

# stratify y_labels의 분포에 따라 분할
X_train, X_test, y_train, y_test = train_test_split(X_features, y_labels,
                                                    test_size=0.2, random_state=0, stratify=y_labels)
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)

 

학습 세트 Shape:(60816, 369), 테스트 세트 Shape:(15204, 369)
 학습 세트 레이블 값 분포 비율
0    0.960438
1    0.039562
Name: TARGET, dtype: float64

 테스트 세트 레이블 값 분포 비율
0    0.960405
1    0.039595
Name: TARGET, dtype: float64

 

위의 결과를 보면 원래 데이터의 분포에 따라 학습 데이터와 테스트 데이터가 잘 분리된 것을 볼 수 있습니다.

 

XGBoost

이제 본격적으로 XGBoost를 통해 학습을 진행보도록 하겠습니다. 학습은 총 500회 반복되면, 100회 이상 정확도 상승이 일어나지 않는다면 조기 종료하도록 하겠습니다.

from xgboost import XGBClassifier
from sklearn.metrics import roc_auc_score

# n_estimators는 500으로, random state는 예제 수행 시마다 동일 예측 결과를 위해 설정. 
xgb_clf = XGBClassifier(n_estimators=500, random_state=156)

# 성능 평가 지표를 auc로, 조기 중단 파라미터는 100으로 설정하고 학습 수행. 
xgb_clf.fit(X_train, y_train, early_stopping_rounds=100,
            eval_metric="auc", eval_set=[(X_train, y_train), (X_test, y_test)])

xgb_roc_score = roc_auc_score(y_test, xgb_clf.predict_proba(X_test)[:,1],average='macro')
print('ROC AUC: {0:.4f}'.format(xgb_roc_score))

 

 

정확도는 84%가 나왔네요. 이제 하이퍼 파라미터를 수정하여 예측 정확도를 더욱 향상해보겠습니다. 시간이 오래 걸리니 100회만 학습을 진행하여 최적의 파라미터를 찾아보겠습니다.

from sklearn.model_selection import GridSearchCV

# 하이퍼 파라미터 테스트의 수행 속도를 향상시키기 위해 n_estimators를 100으로 감소
xgb_clf = XGBClassifier(n_estimators=100)

params = {'max_depth':[5, 7] , 'min_child_weight':[1,3] ,'colsample_bytree':[0.5, 0.75] }

# 하이퍼 파라미터 테스트의 수행속도를 향상 시키기 위해 cv 를 지정하지 않음. 
gridcv = GridSearchCV(xgb_clf, param_grid=params)
gridcv.fit(X_train, y_train, early_stopping_rounds=30, eval_metric="auc",
           eval_set=[(X_train, y_train), (X_test, y_test)])

print('GridSearchCV 최적 파라미터:',gridcv.best_params_) 

xgb_roc_score = roc_auc_score(y_test, gridcv.predict_proba(X_test)[:,1], average='macro')
print('ROC AUC: {0:.4f}'.format(xgb_roc_score))

 

 

찾아낸 최적 파라미터를 기반으로 학습을 1000회 진행하겠습니다.

  

# n_estimators는 1000으로 증가시키고, learning_rate=0.02로 감소, reg_alpha=0.03으로 추가함. 
xgb_clf = XGBClassifier(n_estimators=1000, random_state=156, learning_rate=0.02, max_depth=7,\
                        min_child_weight=1, colsample_bytree=0.75, reg_alpha=0.03)

# evaluation metric을 auc로, early stopping은 200 으로 설정하고 학습 수행. 
xgb_clf.fit(X_train, y_train, early_stopping_rounds=200, 
            eval_metric="auc",eval_set=[(X_train, y_train), (X_test, y_test)])

xgb_roc_score = roc_auc_score(y_test, xgb_clf.predict_proba(X_test)[:,1],average='macro')
print('ROC AUC: {0:.4f}'.format(xgb_roc_score))

 

수행 결과 84.56%로 아주 조금 정확도가 향상된 것을 볼 수 있습니다. 이처럼 트리 기반의 앙상블 기법은 하이퍼 파라미터를 수정한다고 하여 성능이 급격하게 좋아지는 경우는 많지 않습니다. 오히려 최적의 하이퍼 파라미터를 찾기보다는 불필요한 데이터를 제거하는 등 데이터 전처리에 시간을 더 쏟는 것이 더욱 효과가 좋습니다.

 

마지막으로 튜닝 모델에서 각 피처의 중요도를 그래프로 나타내보겠습니다.

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)

 

 

 

LightGBM 모델

from lightgbm import LGBMClassifier

lgbm_clf = LGBMClassifier(n_estimators=500)

evals = [(X_test, y_test)]
lgbm_clf.fit(X_train, y_train, early_stopping_rounds=100, eval_metric="auc", eval_set=evals,
                verbose=True)

lgbm_roc_score = roc_auc_score(y_test, lgbm_clf.predict_proba(X_test)[:,1],average='macro')
print('ROC AUC: {0:.4f}'.format(lgbm_roc_score))

 

예측 정화도는 약 83%가 나왔습니다. 확실히 XGBoost에 비해 속도가 빠른 게 느껴집니다. 하이퍼 파라미터를 수정한 후 다시 성능을 측정해보겠습니다.

 

from sklearn.model_selection import GridSearchCV

# 하이퍼 파라미터 테스트의 수행 속도를 향상시키기 위해 n_estimators를 100으로 감소
LGBM_clf = LGBMClassifier(n_estimators=200)

params = {'num_leaves': [32, 64 ],
          'max_depth':[128, 160],
          'min_child_samples':[60, 100],
          'subsample':[0.8, 1]}


# 하이퍼 파라미터 테스트의 수행속도를 향상 시키기 위해 cv 를 지정하지 않습니다. 
gridcv = GridSearchCV(lgbm_clf, param_grid=params)
gridcv.fit(X_train, y_train, early_stopping_rounds=30, eval_metric="auc",
           eval_set=[(X_train, y_train), (X_test, y_test)])

print('GridSearchCV 최적 파라미터:', gridcv.best_params_)
lgbm_roc_score = roc_auc_score(y_test, gridcv.predict_proba(X_test)[:,1], average='macro')
print('ROC AUC: {0:.4f}'.format(lgbm_roc_score))

 

 

lgbm_clf = LGBMClassifier(n_estimators=1000, num_leaves=32, sumbsample=0.8, min_child_samples=100,
                          max_depth=128)

evals = [(X_test, y_test)]
lgbm_clf.fit(X_train, y_train, early_stopping_rounds=100, eval_metric="auc", eval_set=evals,
                verbose=True)

lgbm_roc_score = roc_auc_score(y_test, lgbm_clf.predict_proba(X_test)[:,1],average='macro')
print('ROC AUC: {0:.4f}'.format(lgbm_roc_score))

 

최종 예측 성능은 약 84%입니다. 이상으로 산타데르 고객 만족 예측을 마무리하도록 하겠습니다.


이번 시간에는 그동안 배운 부스트 기법인 

XGBoost, LightGBM에 대한 실습을 진행해보았습니다.

다음 시간에는 캐글 신용카드 사기 검출 실습을 진행하도록 하겠습니다. 

다양한 데이터 전처리 기법이 사용될 예정이니 많은 기대 부탁드립니다 ㅎㅎ

반응형

'파이썬 머신러닝 완벽가이드' 카테고리의 다른 글

5.1 회귀와 경사하강법  (0) 2022.01.12
4.7 캐글 신용카드 사기 검출  (0) 2022.01.10
4.5 LightGBM 실습  (0) 2022.01.02
4.5 XGboost 실습  (0) 2022.01.02
4.5 앙상블(부스팅)  (0) 2022.01.02