目录
在风控环节中,传统观念A卡为主、B卡C卡为辅,但是在市场逐步饱和、政策利率要求越来越低的背景下,B卡和C卡也越来越重要。本文以简易贷后数据实战催收评分模型,预测在用户逾期后、未来能否催回。
一、数据读取
数据来源某比赛网站,包括逾期用户的年龄、收入情况、家庭人员数、债务情况、历史逾期情况等等,预测变量为订单是否会逾期90天+,数据集中均为数值型变量、且字段较少,所以适合零基础、初学者上手练习。 文末获取数据集
二、变量统计
计算iv及特征缺失率,可以看到仅有两个变量存在少部分缺失,其中历史的逾期变量iv整体偏高。
import toad
def iv_miss(df,var_list,y):
df_tmp=df[df[y].notnull()].copy()
iv_all=toad.quality(df_tmp[var_list+[y]], target=y, indicators = ['iv','unique'])[['unique','iv']]
miss_per=pd.DataFrame(df[var_list].isnull().sum()/(df.shape[0]))
miss_per.columns=['缺失率']
result=pd.concat([miss_per,iv_all],axis=1)
return result.sort_values(['iv'],ascending=False)
df_iv=iv_miss(df_sample,fea_list,y)
df_iv
三、模型构建
这里使用xgb构建二分类模型,使用ks、auc进行评估
查看特征重要性,如下三列分别为分裂次数、平均信息增益、样本覆盖度
def init_params():
params_xgb={
'objective':'binary:logistic',
'eval_metric':'auc',
'silent':0,
'nthread':4,
'n_estimators':1000,
'eta':0.01,
'num_leaves':10,
'max_depth':4,
'min_child_weight':500,
'scale_pos_weight':1,
'gamma':0,
'reg_alpha':2,
'reg_lambda':2,
'subsample':0.8,
'colsample_bytree':0.8,
'grow_policy':'lossguide',
'early_stopping_rounds':50,
'seed':123
}
return params_xgb
def ks_auc_value(y_value,df,model):
y_pred=model.predict_proba(df)[:,1]
fpr,tpr,thresholds= roc_curve(list(y_value),list(y_pred))
ks=max(tpr-fpr)
auc= roc_auc_score(list(y_value),list(y_pred))
return ks,auc
def model_train_sklearn(df,y,fea_list):
params=init_params()
x_train,x_test, y_train, y_test =train_test_split(df[fea_list],df[y],test_size=0.2, random_state=123)
clf=XGBClassifier(**params)
model_sklearn=clf.fit(x_train,y_train,eval_set=[(x_train,y_train),(x_test,y_test)])
train_ks,train_auc=ks_auc_value(y_train,x_train,clf)
test_ks,test_auc=ks_auc_value(y_test,x_test,clf)
dic={
'train_good':(y_train.count()-y_train.sum()),'train_bad':y_train.sum(),
'test_good':(y_test.count()-y_test.sum()),'test_bad':y_test.sum(),
'train_ks':train_ks,'train_auc':train_auc,'test_ks':test_ks,'test_auc':test_auc
}
return dic,clf
model_result,model=model_train_sklearn(df_sample,y,fea_list)
model_result
四、评分使用
C卡用于催收策略,使用预测概率/评分做分箱,如下图,催收策略比如对于bad_rate较低的前2箱可以短信催收、对于中间3-6箱短信催收和点催结合、最后4箱持续电催。
def ks_bins(y_true,y_pred,cut='cut',bins=10,pred='pred'):
'''
cut 分箱方法:cut等距分箱,qcut等频分箱
输出:分箱ks结果
'''
df=pd.DataFrame({
'true':list(y_true),
'pred':list(y_pred), # proba、score都可以
})
if cut=='cut':
df['pred_bin']=pd.cut(df['pred'],bins=bins)
elif cut=='qcut':
df['pred_bin']=pd.qcut(df['pred'],q=bins,duplicates='drop')
df_bin=df.groupby(['pred_bin'])['true'].agg(['count','sum','mean'])
df_bin.columns=['cnt','bad','bad_rate']
df_bin.fillna(0,inplace=True)
df_bin['good']=df_bin['cnt']-df_bin['bad']
df_bin['cum_count']=df_bin['cnt'].cumsum()
df_bin['cum_good']=df_bin['good'].cumsum()
df_bin['cum_bad']=df_bin['bad'].cumsum()
df_bin['cum_bad_rate']=df_bin['cum_bad']/df_bin['cum_count']
if pred=='pred':
df_bin['ks']=df_bin['cum_good']/df_bin['good'].sum()-df_bin['cum_bad']/df_bin['bad'].sum()
elif pred=='score':
df_bin['ks']=df_bin['cum_bad']/df_bin['bad'].sum()-df_bin['cum_good']/df_bin['good'].sum()
return df_bin[['cnt','bad_rate','cum_count','cum_bad_rate','ks']]
round(ks_bins(df_sample[y],df_sample.pred,cut='cut',bins=10,pred='pred'),4)
五、划重点
少走10年弯路
关注威信公众号 Python风控模型与数据分析,回复 风控实战C卡 获取本篇数据及代码
还有更多理论、代码分享等你来拿