본문 바로가기

Lecture ML

머신러닝 강좌 #21] 분류 XGBoost를 이용한 고객 만족 예측

반응형

캐글의 산탄데르 고객 만족 데이터 세트에 대해서 고객 만족 여부를 XGBoost와 LightGBM을 활용해 예측해 보겠습니다.  클레스 레이블 명은 TARGET이며, 이 값이 1이면 불문을 가진 고객, 0이면 만족한 고객입니다. 모델의 성능 평가는 ROC-AUC(ROC 곡선 영역)로 평가합니다. 대부분이 만족이고 불만족인 데이터는 일부일 것이기 때문에 정확도 수치보다는 ROC-AUC가 더 적합니다.

 

데이터를 다운로드 후 TARGET.count()를 확인하면 갯수를 알 수 있습니다. 이를 통해 불만족 비율을 확인해 봅니다.

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

cust_df = pd.read_csv("./dataset/santander/train.csv")
print(cust_df.shape)
print(cust_df.head())
print(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)))

describe()를 통해 데이터 분포도를 확인하면 var3 칼럼의 경우 -99999로 편차가 심한 값을 2로 변환합니다. ID피처는 단순 식별자에 불과하므로 피처를 드롭하겠습니다. 그리도 클래스 데이터 세와 피처 데이터 세트를 분리해 별도의 데이터 세트로 별도로 저정하겠습니다.

print(cust_df.describe())

# print(cust_df.describe())
cust_df['var3'].replace(-999999, 2, inplace=True)
cust_df.drop('ID', axis=1, inplace=True)

#피처 세트와 레입ㄹ 세트 분리. 레이블 칼럼은 DataFram의 맨 마지막에 위치해 칼럼 위치 -1로 분리
X_features = cust_df.iloc[:, :-1]
y_labels = cust_df.iloc[:,-1]
print(X_features.info())
                  ID           var3  ...         var38        TARGET
count   76020.000000   76020.000000  ...  7.602000e+04  76020.000000
mean    75964.050723   -1523.199277  ...  1.172358e+05      0.039569
std     43781.947379   39033.462364  ...  1.826646e+05      0.194945
min         1.000000 -999999.000000  ...  5.163750e+03      0.000000
25%     38104.750000       2.000000  ...  6.787061e+04      0.000000
50%     76043.000000       2.000000  ...  1.064092e+05      0.000000
75%    113748.750000       2.000000  ...  1.187563e+05      0.000000
max    151838.000000     238.000000  ...  2.203474e+07      1.000000

 

학습과 성능 평가를 위해서 원본 데이터 세트에서 학습 데이터 세트와 테스트 데이터 세트를 분리하겠습니다. 비대칭한 데이터 세트이므로 클래스인 Target값 분포도가 학습 데이터와 테스트 데이터 세트에 모두 비슷하게 추출됐는지 확인하겠습니다.

 

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)
train_cnt = y_train.count()
test_cnt = y_test.count()
print(X_train.shape)
print(X_test.shape)

print(y_train.value_counts()/train_cnt)
print(y_test.value_counts()/test_cnt)

 

학습과 테스트 데이터 세트 모두 TARGET의 값의 분포가 원본 데이터와 유사하게 전체 데이터의 4% 정도의 불만족 값(값 1)으로 만들어졌습니다.

(60816, 369)
(15204, 369)
0    0.960964
1    0.039036
Name: TARGET, dtype: float64
0    0.9583
1    0.0417
Name: TARGET, dtype: float64

XGBoost모델 학습과 하이퍼 파라미터 튜닝

먼저 XGBoost의 학습 모델을 생성하고 예측 결과를 ROC AUC로 평가해 보겠습니다. 사이킷런 래퍼인 XGBClassifier를 기반으로 학습을 수행합니다. ROC-AUC이므로 XGBClassifier가 eval_metric은 'auc'로 하겠습니다. 

from xgboost import XGBClassifier
from sklearn.metrics import roc_auc_score

xgb_clf = XGBClassifier(n_estimators=500, random_state=156)
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(xgb_roc_score)

 

위의 결과를 보면  ROC AUC는 0.8413입니다.

다음으로는 XGBoost의 하이퍼 파라미터 튜닝을 수행해 보겠습니다. 칼럼의 개수가 많으므로 과적합 가능성을 가정하고, max_depth, min_child_weigh, colsample_bytree 하이퍼 파라미터만 일차 튜닝 대상으로 하겠습니다. 학습 시간이 많이 필요한 ML모델인 경우 하이퍼 파라미터 튜닝을 수행하는 요령 중 첫 번째는 먼저 2~3개 정도의 파라미터를 결합해 최적 파라미터를 찾아낸 뒤에 이 최적 파라미터를 기반으로 다시 1~2개 파라미터를 결합해 파라미터 튜닝을 수행하는 것입니다.

 

from sklearn.model_selection import GridSearchCV
xgb_clf = XGBClassifier(n_estimators=100)
params = {'max_depth':[5,7], 'min_child_weight':[1,3], 'colsample_bytree':[0.5, 0.75]}
gridcv = GridSearchCV(xgb_clf, param_grid=params, cv=3)
gridcv.fit(X_train, y_train, early_stopping_rounds=30, eval_metric='auc', eval_set=[(X_train, y_train), (X_test, y_test)])

print(gridcv.best_params_)
xgb_roc_score = roc_auc_score(y_test, gridcv.predict_proba(X_test)[:,1], average='macro')
print(xgb_roc_score)

결과로 아래의 parameter가 최적치임을 알게 되었습니다.

{'colsample_bytree': 0.5, 'max_depth': 5, 'min_child_weight': 3}
0.8444548670726981

 

최적의 하이퍼파라미터를 적용하고 튜닝된 모델에서 중요도를 피처 중요도 그래프로 나타내 보겠습니다. xgboost모듈의 plot_importance()메소드를 이용합니다.

xgb_clf = XGBClassifier(n_estimators=1000, random_state=156, colsample_bytree=0.5, max_depth=5, min_child_weight=3)
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(xgb_roc_score)

from xgboost import plot_importance
import matplotlib.pyplot as plt

fig, ax = plt.subplots(1,1,figsize=(10,8))
plot_importance(xgb_clf, ax=ax, max_num_features=20, height=0.4)
plt.show()

반응형