Python作业集:信用卡还款违约预测

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()
data.info() output

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)
  • 违约数据存在不平衡,与现实状况相仿,存在违约行为的客户少于按时还款人数
catogorical feature distribution
查看连续型变量分布
  • 绝大多数的授信额度都在100000以内,其中授信额度为50000的人数最多
  • 如果以违约划分的话,授信额度高的客户违约也相对较多,主要的违约还是集中在50000的额度周围
discrete feature distribution
用户特征
  • 教育程度较高的客户年龄更低,研究院、大学背景的用户平均年龄在35岁左右
  • 已婚客户的年龄大于单身客户,平均年龄在40岁左右
用户特征
授信额度和用户特征
  • 对于年轻客户群体的授信额度低于总体水平,可能是考虑到收入相对也要低于中年客户
  • 受教育程度越高的客户额度授信也会更高
  • 已婚客户的额度授信更高
授信对比 (年龄、教育、婚姻).jpg

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()   
features importance

在随机森林模型中, 对于模型分类影响最大的前几个因素依次为:

  • 最近一次的还款情况 (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.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352