在风控环节中,传统观念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_xgbdef 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,aucdef 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,clfmodel_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)
代码与数据获取
独学而无优则孤陋而寡闻,技术要学会交流、分享,不建议闭门造车。
技术交流与答疑、源码获取,均可加交流群获取,群友已超过2000人,添加时最好的备注方式为:来源+兴趣方向,方便找到志同道合的朋友。
方式①、微信搜索公众号:Python学习与数据挖掘,后台回复:催收评分卡
方式②、添加微信号:dkl88194,备注:催收评分卡
资料1
资料2
我们打造了《数据分析实战案例宝典》,特点:从0到1轻松学习,方法论及原理、代码、案例应有尽有,所有案例都是按照这样的节奏进行表述。