Part 1 数据集和数据字典
数据集包含某银行信用卡部门4月至6月违约信息,人口信息,信用额度,还款状况,还款金额,历史账单,任务是用模型预测用户的违约情况。(https://www.kaggle.com/uciml/default-of-credit-card-clients-dataset)
ID: 客户ID
LIMIT_BAL: 额度
SEX: 性别(1=male, 2=female)
EDUCATION: (1=graduate school, 2=university, 3=high school, 4=others, 5=unknown, 6=unknown)
MARRIAGE: 婚姻状况 (1=married, 2=single, 3=others)
AGE: 年龄
PAY_0: 还款状态 - 9月份(-1=pay duly按时, 1=逾期1个月, 2=逾期2个月, … 8=逾期8个月, 9=逾期9个月以上)
...
BILL_AMT1: 账单金额 - 9 月份
...
PAY_AMT1: 还款金额 - 9月份
...
default.payment.next.month: 下月是否违约 (1=yes, 0=no)
- 使用分类模型预测下月是否违约
- 哪个特征对于分类器的影响因素更大
Part 2 数据获取
查看数据集
- 这次的数据集共有30000行客户的还款记录
- 特征值有25列,包含有关于客户的基本信息,每月的还款记录,以及需要我们预测的目标-是否违约
# read the data
df = pd.read_csv('UCL_Credit_Card.csv')
# glimpse at the data
df.head()
df.info()
Part 3 数据清洗
检查数据(缺失,异常)
缺失值处理 暂时无缺失值
编码异常 由原题意中判断个别有编码异常:
- EDUCATION 教育背景一栏代表的信息中4为'others',5和6却为'unknown'. 将他们统一归为4 'others'
- MARRIAGE 婚姻状况一栏中也一样出现了0为'unknown',3为'others'。统一归为3 'others'
命名不规范 对列名重新命名,[default.payment.next.month] >>> [def_pay], [pay_0] >>>[pay_1]
# relabel EDUCATION information
fil = (data.EDUCATION == 5) | (data.EDUCATION == 6) | (data.EDUCATION == 0)
data.loc[fil, 'EDUCATION'] = 4
# relabel MARRIAGE information
data.loc[data.MARRIAGE == 0, 'MARRIAGE'] = 3
# rename column
data = data.rename(columns={'default.payment.next.month':'def_pay','pay_0':'pay1'})
Part 4 数据探索
查看类别型变量的分布
- 数据集中包含的女性客户(2)比男性客户(1)多
- 客户受教育程度较高,多为研究院(1)和大学学历(2)
- 违约数据存在不平衡,与现实状况相仿,存在违约行为的客户少于按时还款人数
查看连续型变量分布
- 绝大多数的授信额度都在100000以内,其中授信额度为50000的人数最多
- 如果以违约划分的话,授信额度高的客户违约也相对较多,主要的违约还是集中在50000的额度周围
用户特征
- 教育程度较高的客户年龄更低,研究院、大学背景的用户平均年龄在35岁左右
- 已婚客户的年龄大于单身客户,平均年龄在40岁左右
授信额度和用户特征
- 对于年轻客户群体的授信额度低于总体水平,可能是考虑到收入相对也要低于中年客户
- 受教育程度越高的客户额度授信也会更高
- 已婚客户的额度授信更高
Part 5 训练模型
这部分主要通过代码块来展示训练的过程,大致步骤包含:
- 导包,设置参数
- 设定目标值和特征值
- 拆分数据,训练集和验证集
- 将训练数据导入模型
- 用模型计算预测值
# ***********************load packages***********************
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import roc_auc_score
# ***********************set parameters***************************
RFC_METRIC = 'gini' #metric used for RandomForrestClassifier
NUM_ESTIMATORS = 100 #number of estimators used for RandomForrestClassifier
NO_JOBS = 4 #number of parallel jobs used for RandomForrestClassifier
RANDOM_STATE = 2018
VALID_SIZE = 0.20 # simple validation using train_test_split
# *********************define target and predictors*********************
target = 'def_pay'
predictors = [ 'LIMIT_BAL', 'SEX', 'EDUCATION', 'MARRIAGE', 'AGE',
'PAY_1', 'PAY_2', 'PAY_3', 'PAY_4', 'PAY_5', 'PAY_6',
'BILL_AMT1','BILL_AMT2', 'BILL_AMT3', 'BILL_AMT4', 'BILL_AMT5', 'BILL_AMT6',
'PAY_AMT1', 'PAY_AMT2', 'PAY_AMT3', 'PAY_AMT4', 'PAY_AMT5', 'PAY_AMT6']
# ***********************train test split***********************
train_df, val_df = train_test_split(data, test_size=VALID_SIZE, random_state=RANDOM_STATE, shuffle=True )
# ***********************calling the model with pre-fix parameter***********************
clf = RandomForestClassifier(n_jobs=NO_JOBS,
random_state=RANDOM_STATE,
criterion=RFC_METRIC,
n_estimators=NUM_ESTIMATORS,
verbose=False)
# ****************fitting the model***********************
clf.fit(train_df[predictors], train_df[target].values)
# ***********************predict the value in test set******************
preds = clf.predict(val_df[predictors])
Part 6 模型评估
# ****************display ROC-AUC score**************
roc_auc_score(val_df[target].values, preds) # 0.661340
# ****************plot the features importance**************
tmp = pd.DataFrame({'Feature': predictors, 'Feature importance': clf.feature_importances_})
tmp = tmp.sort_values(by='Feature importance',ascending=False)
plt.figure(figsize = (7,4))
plt.title('Features importance',fontsize=14)
s = sns.barplot(x='Feature',y='Feature importance',data=tmp)
s.set_xticklabels(s.get_xticklabels(),rotation=90)
plt.show()
在随机森林模型中, 对于模型分类影响最大的前几个因素依次为:
- 最近一次的还款情况 (PAY_1)
- 年龄 (AGE)
- 最近一次的账单 (BILL_AMT1)
- 授信额度 (LIMIT_BAL)
试用XGBoost重复模型训练
import xgboost as xgb
MAX_ROUNDS = 1000 #lgb iterations
EARLY_STOP = 50 #lgb early stop
OPT_ROUNDS = 1000 #To be adjusted based on best validation rounds
VERBOSE_EVAL = 50 #Print out metric result
# Prepare the train and valid datasets
dtrain = xgb.DMatrix(train_df[predictors], train_df[target].values)
dvalid = xgb.DMatrix(val_df[predictors], val_df[target].values)
#What to monitor (in this case, **train** and **valid**)
watchlist = [(dtrain, 'train'), (dvalid, 'valid')]
# Set xgboost parameters
params = {}
params['objective'] = 'binary:logistic'
params['eta'] = 0.039
params['silent'] = True
params['max_depth'] = 2
params['subsample'] = 0.8
params['colsample_bytree'] = 0.9
params['eval_metric'] = 'auc'
params['random_state'] = RANDOM_STATE
model = xgb.train(params,
dtrain,
MAX_ROUNDS,
watchlist,
early_stopping_rounds=EARLY_STOP,
maximize=True,
verbose_eval=VERBOSE_EVAL)
The best validation score (ROC-AUC) was 0.78, for round 453.