新闻中心

逾期回款率预测

逾期回款率预测

谈一谈我理解的贷后催收_客户_问题_还款

原标题:谈一谈我理解的贷后催收

催收要解决的是客户回款问题,但催收本身具体是一个怎样的问题,还需要结合案例,具体问题具体分析。作者结合案例,用浅显易懂的大白话带你了解贷后催收,一起来看看。

一、催收是个怎样的问题

毫无疑问,催收要解决的问题是客户回款。但催收本身是一个怎样的问题,首先来看一个案例:

举例:针对逾期客群A,在其逾期的1、7、15、21(天)时发送话术“模板1”的短信,在其逾期的24、27、30天进行人工催收并发送话术“模板B”的短信。

由此可见,催收工作主要包括以下的6个方面:

对什么样的客户?

在什么时间?

用什么催收方式,如短信、IVR、人工电催、信函、委外等?

以什么频率,即强度?

用什么话术?,如提醒、谈判、施压、警告等

最终促使客户还款,是终极目标,个人认为,在这五点里面涉及四个层面的策略:

分群策略:解决对什么样客户的问题,将待催客户按不同标准分为不同的客群;

分案策略:解决在客户是否逾期以及逾期多久后,将不同客群客户分派给谁,比如不同技能的催收团队、甚至个人、机器人等;

拨打策略:解决怎么拨打电话的问题,如打什么电话,频次怎样等;

话术策略:解决如何提醒、沟通施压、减免等的问题,因客户反馈具备不可预期,此处多为原则性指导,要随客户反馈随机应变。

总之,催收就是将各种催收手段,以适当的方式与不同的逾期客户匹配,从而达到回款效果好、催收成本可控(最优)的目标。

二、催收客户分群

此处不考虑大额、抵押、欺诈等各类场景,主要考虑小额信贷业务,该类场景按“业务+客群”分群模式居多。通常情况下,按照回款的难易程度将客户分为以下三类:

数据显示,

逾期客户呈现“早期客户量多,回款容易;中后期客户量少,回款难度较高”的特点

。所以在此基础上,结合监管要求、考核要求、业务运营等多方面的考量,催收客户的分群通常是在逾期阶段的基础上来进行划分。如,M0、M1、M2等。然后,通常通过催收模型的方式进一步细分。常用的有以下几类:

在催收过程中,逾期早期,主要寻找还款困难的客户,促使其早日还款;逾期中后期,主要寻找还款可能性高的客户,尽可能多的收回欠款

。可以通过上述分群的方式,从早期客户中寻找难回款的客户,以及中后期客户中相对容易回款的客户。

三、分案策略

客户入催后,完成分群后就需要将客户派发给相应的话务员或机器进行催收。主要涉及3个问题:

什么时候分派?

什么模式分派?

派发给谁?

首先解决什么时候分派的问题,什么时候分派需要考虑三个方面的因素:

客户服务。比如,客户刚逾期,通常需要发送一条提醒短信通知客户还款,起到尽职义务。如果没有提醒,后续客户还可能会投诉,并且存在升级投诉的可能(当然,大环境好的时候,也有些公司因收益的因素,可能会采取不同的策略);

回款率(成本):以刚逾期客户举例,可通过观察客群在无催收情况下,逾期后30天内的回款曲线变化来判定回款率变化的拐点,可以在回款率下降前进行催收,可省去很多无效拨打。

合规:如《信用卡管理办法》中明确要求“发卡银行应当及时就即将到期的透支金额、还款日期等信息提醒持卡人”(每个公司对于这块,归属部门可能不同)。

其次,采取什么分案模式,方面通常有抢案模式和派发模式。人工催收时,分案和抢案的情况可能二选一或组合使用。以下是我对两种模式理解:

四、拨打策略

分案完成后,就需要联系客户了(短信、IVR、人工电话),如何联系也涉及三个方面的问题:

什么时候,什么频率?

拨打给谁,本人or联系人?

拨打模式?

首先,什么时候拨打,主要考虑三个方面的问题:

合规:比如法规要求,一天之中晚上九点之后和早上八点之前禁止拨打,拨打客户的频率也不可过高,否则引起投诉骚扰。

接通率:不同客户,在不同时间段拨打,其接通率存在较大差异,比如有些工人上夜班或者工作时不能带手机(也有简单粗暴的,直接自动外呼,联系不上就间隔一段时间后再继续拨打)。之前有一篇有关机器学习的策略实践,感兴趣可参见之前的一篇文章:《记一次催收策略/模型实践——提升客户可联率》

客户体验:比如节假日、午休期间的特殊处理、客户承诺还款当天再次进行提醒的处理等。

其次,拨打给谁方面,主要考虑合规问题 。比如首拨是不可以打给客户的紧急联系人的,一定是在多次联系不上本人的时候才可拨打,拨打给联系人时还要注意措辞,避免给客户造成生活上或工作上的影响。在充分拨打客户且联系不上时,才可以联系客户的紧急联系人及其他联系人。

最后,拨打模式,主要考虑拨打效率和可联率(客户维度的,不同于接通率),自动外呼拨打效率高,通常都采用自动拨打的模式。按自动外呼拨打接通与否,又分为预测式与预览式:

除了预测式、预览式外呼,还有坐席手动外、机器人外呼,人机结合外呼等方式,这里重点说下人机结合,是由机器人根据配置好的外呼模板进行外呼,接通后先由机器人进行服务,检测意向后无缝转人工。

通常业绩压力较大的时,会多向业务偏移,而监管趋严时,又会特别注重合规。拨打策略调整经常需要在两者之间找平衡。不同场景下,侧重点也会有所差异。

作者:王小宾;微信公众号:一起侃产品

本文由@并不跳步交叉步 原创发布于人人都是产品经理。未经许可,禁止转载。

题图来自 Unsplash,基于 CC0 协议

返回搜狐,查看更多

责任编辑:

百度知道 - 信息提示

百度知道

>

提示信息

知道宝贝找不到问题了>_<!!

该问题可能已经失效。

返回首页

15

秒以后自动返回

信贷风控中的收入与还款能力预测 - 知乎

业务背景

信贷风控问题主要可以拆解为三部分:欺诈、还款能力和还款意愿。还款能力在整个信贷流程中起了非常重要的作用,特别是对于致力于做大额长期信贷产品来说。从贷前来看,用户的收入直接关乎用户额度的高低。从贷中来看,用户收入的高低以及收入的稳定性直接影响额度的提升。从贷后逾期来看,对于还款意愿低的用户还能通过催收方式提升回款率,但是对于还款能力低的用户本就没有稳定的收入,更容易变成坏账。

本文从策略规则和模型的视角介绍一些收入和还款能力预测的方法。

目录

Part 1. 数据准备

Part 2. 通过策略规则进行收入预测

Part 3. 通过模型进行收入预测

Part 4. 通过模型进行还款能力预测

Part 5. 总结

版权声明

参考资料

Part 1. 数据准备

在介绍具体的方法之前,我们先来梳理一下哪些数据可以用于收入和还款能力的预测,主要可以分为强相关数据和弱相关数据。

强相关数据是指能直接推算用户收入情况的数据,主要包括信用卡额度、房贷、公积金等。弱相关数据是指能间接反映用户的收入水平,可用于模型中预测用户的收入和还款能力,主要包含反映用户消费能力的信用卡账单、电商购物、运营商账单,反映用户个人信息的手机信息、学历、自填收入、是否有车、地址等。下面 我们逐个进行介绍。

图1. 收入相关数据

1. 信用卡

信用卡数据主要包含两部分,一部分是信用卡额度,另一部分是信用卡账单。信用卡额度反映了银行对用户的授信情况,是推算收入的强相关数据。信用卡账单中的额度使用率、消费金额等则体现了用户的消费水平,可用于预测用户的收入和还款能力。

2. 房贷

用户如果有房贷,则说明该用户是一个有房用户,资质不会太差。其次通过月房贷还款额则可推算出用户的收入情况。

3. 公积金

公积金数据和收入是直接相关的,是银行对用户进行授信时常用的数据。并且公积金数据除了能推算收入的高低,还能反映用户收入的稳定情况。

4. 电商购物

目前年轻人都习惯于网络购物,因此电商购物数据能很好的反映用户日常消费水平。通过电商消费数据我们可以挖掘用户最大单笔支出金额、月平均消费水平、购物类别偏好,消费稳定性等特征,帮助我们预测用户的收入和还款能力。但是需要注意的是,因为受6.18,双11,双12等活动的影响,用户在大型活动前后的消费行为会减少,在活动时间节点爆发,在构建特征的时候需要注意。

5. 运营商

运营商数据经常用于反欺诈环节,在网时长大于6个月通常是准入的必备条件,那么运营商中哪些数据和收入相关呢?运营商每月的账单数据和充值数据从某种角度上体现用户的消费能力,可用于收入的预测。

6. 手机

用户的手机品牌可以很好的反映用户的消费能力,为此我们可以对不同的手机品牌和手机价格做一个映射关系,用户后续手机品牌特征的开发。另外如果用户的手机上安装了大量的借贷赌博类app,则该用户是一个急缺钱的偏坏用户,往往还款能力也较低。这些特征都可以用于收入和还款能力的预测。

7. 学历/自填学历

学历和收入从整体上来来看还是正相关的,当然不排除某些个例。

8. 自填收入

谈到自填收入,可能很多人会觉得不靠谱。自填收入的绝对值的确是不准确的,但是相对数值还是有可参考价值的,即对自填收入进行分箱后,还是会保留Ranking价值。说白了,自填收入是需要有想象力的,而虚报的收入往往和真正的收入呈正相关,就好比一个月收入5000的用户可能会虚报自己月收入1-2w,但是不太可能虚报自己月收入10w。

9. 是否有车

有车用户相比于无车用户还是会更优质一些,从某种程度上体现了用户的消费收入水平。

10. 地址

地址可以分为身份证地址、工作所在地地址、家庭地址等,这些都和收入有着较弱的相关性。

Part 2. 通过策略规则进行收入预测

上面 介绍了可用于进行收入预测的数据,主要分为强相关数据和弱相关数据,本章主要介绍如果利用强相关数据进行收入预测。

1. 公积金

相信大家都有申请信用卡的经历,在申请信用卡的过程中我们需要填一大堆资料,包括工作单位、收入、学历、住址等,另外一般还需要我们提供相应的公积金缴纳数据。在经过漫长的等待之后,银行会给我们寄来相应额度的信用卡,到此我们成功申请到了一张信用卡。

银行给我们的额度基本是根据我们的收入情况给出的,特别是一些大行,因为有一整套完整的授信提额风控策略,所以额度会给得相对保守(除非提供有房有车证明等)。那么银行是如何推算我们的收入呢?

缴纳过公积金的同学都知道,

公积金月缴纳额=工资base✖️不同城市的缴纳比例✖️2(个人+公司)

,其中工资base在每个城市有相应的上限。那么如果有用户的公积金月缴纳额,那么我们是不是能反推出相应的工资base,即简单又准确,而且还能和自填收入进行校验。当然,为了收入预测更加精确,我们需要对不同的城市构建一张不同的缴纳比例映射表。

2. 信用卡额度

回到上面信用卡授信的案例,大行因为本身数据全,风控能力强,可以很好的刻画新用户的信用风险,从而进行合理授信,那么对于那些风控能力弱的中小行,他们会怎么进行授信呢。

用户如果拥有大行的信用卡是不是意味着用户通过了大行的风控审查,那肯定是一个较优质客户了。那对于小行来说,完全可以利用大行的授信额度对新用户进行授信,并此基础上给与相应的提额,即减少了风控成本(参考大行信用卡的额度)也提高了吸引力(额度高于大行信用卡额度),何乐为不为。

参照这个思路,对于信贷机构来说,完全可以通过用户的信用卡额度来推算用户的收入,例如通过去掉大额信用卡后取平均或者取平均后除以相应的系数作为用户的收入。需要注意的是,一定要排除大额信用卡带来的失真影响。

3. 房贷

有过住房贷款的同学会知道,在按揭的时候,每月还款额一般不能超过月收入的50%,因此利用

未结清房贷的月还款额✖️相应的系数

便能推算出相应的收入水平。

Part 3. 通过模型进行收入预测

当我们只有反映用户消费水平和个人信息的弱相关数据的时候,我们可以通过建模的方式来预测用户的收入。

当然这里建模的前提是我们已经有一批用户的收入数据作为Y标签用于模型训练

。下面 我们进行具体的介绍:

1. 确定训练目标

针对收入预测,最理想的方法是通过回归的方法来预测收入的具体值,这就要求必须有大量无偏样本的收入数据进行训练支持,如果训练数据不够,模型回归预测的效果往往不佳,但是大量的收入数据通常是比较难获取的,这个时候我们可以通过二分类的方法进行解决。

根据收入数据确定一个cutoff,从而将收入分为高和低(也就是1和0),例如已5000元作为cutoff,那么收入大于5000的则视为1,收入低于5000的则视为0。

这里大家可能会问,cutoff该如何定义?根据笔者的经验,cutoff定义的越高,则预测的结果和逾期的相关性越高。例如我们定义cutoff为15000时,那么收入高于15000的人群和收入低于15000的人群差异越明显,这时候收入模型从某种角度来说就是在预测逾期。

所以在定义cutoff的时候看各自的需求是什么了,如果只是想要预测收入,那cutoff可以在平均收入线,如果希望和逾期高相关,那可以定义的高一些,笔者更推荐前者。

2. 特征工程

可用的数据源在上面 章节已经讲过,根据业务理解可以开发相关的特征,并进行一些特征衍生,如果要使用一些存量数据源,必须进行相关的数据有效性分析。

3. 模型选择

在模型的选择上可以选用机器学习模型或者评分卡模型。如果样本量小,偏差高的话,则可以选用解释性更好的评分卡模型。

4. 模型评估

关于模型效果评估可以从两个方面进行:

一是评估收入的准确性、合理性

二是评估收入对贷后逾期表现的排序性

Part 4. 通过模型进行还款能力预测

那么如果我们只有反映用户消费水平和个人信息的弱相关数据的时候,没有相应的收入数据作为Y标签用户训练时,我们该如何处理,是不是就不能进行预测了?

这个时候我们很难直接预测用户的收入到底是多少,但是我们可以通过这些数据来预测用户的还款能力是高还是低。换句话说就是,我们没法直接预测收入的绝对值,但是我们可以预测收入的相对值,即收入的排序水平(还款能力的高低)。

在建模之前,这里有个问题亟需我们解决,那就是如何定义一个能衡量用户还款能力高低的Y标签 ?

相信大家在建PD模型的时候,都会以给定表现期内发生某种程度的逾期行为就认为是坏样本了,例如在MOB6内发生过DPD30+。那么,大家可以思考下对于有怎样贷后表现表现的用户我们可以认为是还款能力低的用户?

图2. 还款能力的定义

用户从拿到借款开始,如果第一、二期就开始逾期,那么这类用户要么是欺诈用户,要么是高信用风险用户(不良嗜好人群、高负债人群),对这类客群的识别属于反欺诈环节的工作,对应于T1时间段。对于一个有借贷需求的正常用户,因为刚借到钱并不会很快花完,因此前几期的还款往往是正常的(按时还款或者轻微逾期,例如逾期1-3天就还款了),对应于T2时间段。但是对于收入低或者收入不稳定的用户,随着时间的推移,逾期会开始变得严重起来,发生DPD7+、DPD15+等,对应于T3时间段。对于还款能力正常的用户来说,它在T4(T2+T3)时间段内,还款表现往往都是正常的。因此我们可以这样定义:

人群:T2时间段内正常还款的用户(这里的正常可以指发生轻微逾期也可指完全没有逾期行为)

Bad(还款能力弱):T3时间段内发生过较严重逾期(DPD15+、DPD30+等)

Good(还款能力正常):T3时刻和T2时刻还款表现相同,即正常还款

如果有相应的收入数据,可以定义完Y标签后结合收入数据进行校验,看定义的是否合理。定义完Y标签后可以按照Part3中介绍的方法进行建模来预测还款能力的高低。

Part 5. 总结

本文主要介绍了如何通过与收入相关的数据来预测推算收入或者是预测用户还款能力的强弱。收入数据是整个信贷风控业务中的关键数据,支撑着贷前的出额授信、贷中的额度管理(提额降额)以及贷后的催收策略。我们需要在实践中不断发现变量和收入之间的关系,以此来更好的推断用户收入。当有收入强相关数据时,我们还是应该先以强相关数据为主,毕竟它们的准确率可以得到很好保证。

收入预测的方法还有很多,在此抛砖引玉,欢迎大家讨论。

版权声明

欢迎转载分享,请在文章中注明作者和原文链接,商业转载请联系作者获得授权,非商业转载请注明出处。

原文作者:过一点画一条直线(知乎ID)

知乎专栏:数据化风控

原文链接:

https://

zhuanlan.zhihu.com/p/14

6461086

关于作者:

本人就职于某科技公司从事风控算法策略、数据挖掘相关工作,欢迎互相交流,共同成长。

429 Too Many Requests

429 Too Many Requests

openresty

信用卡逾期预测数据分析报告 - 知乎

一、数据介绍

某金融机构的风控需求分为贷前分析和贷后分析,在发放贷款之前需要审核贷款人的资质,以此减少逾期风险,根据贷后表现数据,以此判断各指标的设立能否有效判别是否发生逾期风险。

某机构的逾期数据,包含的字段有:

字段

含义

id

用户编号

bad

是否逾期

wealth

财富级别

max_unpay_day

最大逾期天数

score

评分

age

年龄

period

分期期数

education

学历背景

数据链接:

https://

mp.csdn.net/console/upD

etailed

二、需要分析的问题

根据贷后表现数据,以此判断各指标的设立能否有效判别是否发生逾期风险

三、分析思路

数据预处理

查看数据分布情况

特征筛选

各特征对逾期的影响程度

建模分析整体指标评判逾期的准确率

结论

三、数据分析

1.数据预处理

import laprasimport pandas as pdimport numpy as npimport matplotlib.pyplot as pltfrom sklearn.model_selection import train_test_splitimport seaborn as snsfrom sklearn.linear_model import LogisticRegressionfrom sklearn.neighbors import KNeighborsClassifierfrom sklearn.tree import DecisionTreeClassifierfrom sklearn.metrics import accuracy_scoreplt.rcParams['font.family'] = ['sans-serif']plt.rcParams['font.sans-serif'] = ['SimHei']df=pd.read_csv('./creditcard_demo.csv')print(df.head())print(df.info())

图1

图2

可以看到有缺失值,因为max_unpay_day缺少值过多,不适合使用填充的方法,因此将缺失值删除

df=df.dropna()print(df.head())print(df.info())

图3

图4

由于缺失值较多,删除缺失值之后剩余的数据只有406行,数据量较少,最后模型讨论的结果可能存在一定偏差。

2.数据分布情况

print(df.drop('id',axis=1).describe())

图5

从图5可以看到各列都是用数值来表示的,数据很整洁,不需要做进一步的特征清洗

df_columns1=['wealth', 'max_unpay_day', 'period', 'education']print(df_columns1)fig,axes=plt.subplots(2,2,figsize=(15,30))for i,value in enumerate(df_columns1): #print(i) #print(value) plt.subplot(2,2,i+1) sns.countplot(x=value,data=df)plt.show()df_columns2=['score','age'] print(df_columns2)fig,axes=plt.subplots(2,1,figsize=(15,30))for i,value in enumerate(df_columns2): #print(i) #print(value) plt.subplot(2,1,i+1) sns.countplot(x=value,data=df)plt.show()

图6

图7

由于'score'和'age'两列数据间距分布较为密集,将该两列单独放在一个画布中显示。图6和图7展示了'wealth'、'max_unpay_day'、'period'、'education'、'score'和'age'这6个特征向量的统计分布情况。例如,wealth得分在4.0的人数最多,max_unpay_day在171天最多。

3.特征筛选

x=df.drop(['id'],axis=1) # print(x)y=df[['bad']] # print(y)x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.3,random_state=5)

建立特征工程,'wealth'、'max_unpay_day'、'period'、'education'、'score'和'age'作为特征,'bad'作为目标。在lapras中建立特征工程需要把因变量和自变量同时放入训练集中。

【判断各特征是否有效】

iv=lapras.quality(x_train,target='bad')print(iv)

图8

IV值表示变量的预测能力,IV值越大越显著,IV值不会为负值,通常IV值大于0.02,说明该变量选取较好,因此判断六个特征可以有效判别是否逾期。

【判断特征相关性】

vif=lapras.VIF(x_train.drop(['bad'],axis=1))print(vif)

图9

一般来说VIF值大于10说明特征之间具有相关性,会相关影响,需要剔除VIF值大于的特征。图9中的大部分特征的VIF值大于10,可能的原因是数据量小造成的,只有406组数据。在这种情况下,我们将VIF值放宽至15选取互不相关的特征。

vif=lapras.VIF(x_train.drop(['bad','max_unpay_day','age'],axis=1))print(vif)

图10

图10 是满足不相关要求的特征,这里存在一个不合理之处,就是把年龄剔除了,从逻辑上说,贷款的逾期风险跟年龄是存在很大关系的,年龄是一个很重要的影响因素,因而不能剔除年龄特征。

4.各特征对逾期的影响程度

#筛选变量,设定选取的变量IV值要大于0.04,相关系数大于0.9train_selected,dropped=lapras.select(x_train.drop(['max_unpay_day'],axis=1),target='bad',iv=0.04,corr=0.9,return_drop=True,exclude=[])#设定分箱函数c=lapras.Combiner()train_model=c.fit(train_selected,y='bad',method='dt',min_samples=0.05,n_bins=10)#将各特征与因变量的关系绘制出来cols=list(lapras.quality(train_selected,target='bad').reset_index()['index']) #获取特征名列表print(cols)for col in cols: lapras.bin_plot(train_model.transform(train_selected[[col,'bad']],labels=True),col=col,target='bad')

图11

图12

图13

图14

图15

图11至图15展示了各特征在各个区间内对逾期的影响,具体来看:

在图11中,财富得分在[5.5,6.5)区间的人群的逾期风险最低,财富逾期较低或者较高的人群的逾期风险都较大。

在图12中,得分在[206,213.5)、[257,+∞)区间的人群的逾期风险较低,且得分高于257之后,呈现得分越高,逾期风险越低的变化关系。

在图13中,年龄对逾期风险的影响呈现年龄越高,逾期风险越低的变化,年龄在[25.5,29.5)区间的人群的逾期风险较低。

在图14中,教育得分超过3.5以后,呈现教育得分越高,逾期风险越高的变化趋势,(-∞,2.5)和[2.5,3.5)区间的逾期风险较低,两者差别不大。

在图15中,分期期数越高,逾期风险越高。

六个特征对比来看,财富、最大逾期天数、得分和年龄波动幅度较大,说明对逾期风险较为敏感,教育和分期期数波动幅度不大,说明对逾期风险敏感度不强。

5.建模分析整体指标评判逾期的准确率

modelx=df.drop(['id','bad','max_unpay_day'],axis=1).values modely=df['bad'].valuesmodelx_train,modelx_test,modely_train,modely_test=train_test_split(modelx,modely,test_size=0.3,random_state=5)print('训练集的行数:',modelx_train.shape[0])print('训练集的列数:',modelx_train.shape[1])

图16

logit=LogisticRegression() logit_model=logit.fit(modelx_train,modely_train) predict=logit_model.predict(modelx_test) acc=accuracy_score(modely_test,predict) print('逻辑模型预测的准确率为:{:.3f}'.format(acc)) knn=KNeighborsClassifier() knn_model=knn.fit(modelx_train,modely_train) predict=knn_model.predict(modelx_test) acc=accuracy_score(modely_test,predict) print('K-NN模型预测的准确率为:{:.3f}'.format(acc)) tree=DecisionTreeClassifier() tree_model=tree.fit(modelx_train,modely_train) predict=tree_model.predict(modelx_test) acc=accuracy_score(modely_test,predict) print('决策树模型预测的准确率为:{:.3f}'.format(acc))

图17

使用了逻辑模型、K-NN模型和决策树模型三种模型拟合了六个特征对逾期的影响关系,使用测试集测试表明,逻辑模型能根据特征预测是否逾期的准确率达到0.926,K-NN模型能根据特征预测是否逾期的准确率达到0.877,决策树模型能根据特征预测是否逾期的准确率达到0.762,说明逻辑模型较为适合预测逾期风险,这也说明该六个特征可以较为良好的来判别是否逾期。

四、结论

1、财富、最大逾期天数、得分、年龄、教育和分期期数的IV值均大于0.02,说明这六个特征可以有效判别是否逾期。

2、财富、最大逾期天数、得分、年龄、教育和分期期数这六个特征之间存在严重的相关性,剔除最大逾期天数和年龄之后,剩余的特征之间无相关性,但由于年龄较为重要,保留该特征。

3、财富、得分和年龄波动幅度较大,说明对逾期风险较为敏感,教育和分期期数波动幅度不大,说明对逾期风险敏感度不强。

4、逻辑模型比K-NN模型和决策树模型较为适合预测逾期风险,预测逾期风险的准确率达到0.926。

补充----------------------------------------------------------------------------------

在KNN建模过程中,可以使用交叉验证选择最合适的K值

list=[1,5,10,15,20]cv_score=[]model_list=[]for k in list: knn_model=KNeighborsClassifier(k) score=cross_val_score(knn_model,modelx_train,modely_train,cv=10,scoring='accuracy') cv_score.append(score.mean()) model_list.append(knn_model)best_k=np.argmax(cv_score)best_model=model_list[best_k]best_train_model=best_model.fit(modelx_train,modely_train)y_predict=best_train_model.predict(modelx_test)print(accuracy_score(modely_test,predict))

可以看到,选择最佳的K值进行预测之后,准确率从之前的0.877提高到了0.885,说明K值的设定影响着模型的结果,这也是KNN模型的一大缺点之处。

逾期后,欠款1W的比欠10W的起诉概率高是啥情况?3个原因你没想到|法院|回款率_网易订阅

美翎律所

专业、高效、快捷

大家好,今天也是为逾期人操心的一天!我们都说过,现在真的已经到了一个“批量起诉”的时期,为什么这么说呢?作为律所,我们每天都能收到各大平台,包括卡片方发送过来的资料,这些“资料”往往都是很多正要被起诉的逾期人,我们称这为“批量起诉”!在处理这些起诉案件的时候,我们发现,有的人逾期金额少,有的人金额大,但是同样都被起诉了!而且针对某些特定的平台,金额小的往往占大多数,难道他们没有金额大的客户吗?不是的,而是针对于某些平台的政策和策略,起诉“小”的反而更划算,到底为什么呢?今天没翎就来给大家分析分析!

很多人觉得欠的越多的人越应该先被起诉,尤其是会看到一些后台留言说:那些几十万的都没事,我这一两万的小数目,人家更不会起诉。但其实并不是的,有时候,欠1万比欠10万的起诉概率高也是有可能的。今天就从三个维度来给大家分析一下为什么。

首先你要看你借的是哪个平台,有的人他是借了10万,但他专门找不正规的平台借,这些平台见不得光,自然也不敢起诉,或者就算被起诉了,也会因为不合规而被法院直接驳回。而有的他虽然金额很低,可找的是卡片方这样正规机构的大平台,他们利息合规,操作合法,流程清晰,这样的平台和那些杂牌平台起诉概率肯定是不一样的。

这时候有人就要说了,那如果是正规的卡片方为啥低的被起诉,高的却没有呢?这种情况就要看你借的这家卡片方的客户容量高不高,客户体量大的,自然他的坏账相对就更多,顾不过来起诉是很正常的。但是你要借的是地方性的银行,那他们针对你可就很有优势了,当地机构诉讼成本低,并且他们的客户单量少,对你肯定是盯得很紧的。虽然同为银行,同样正规,客户体量小的,诉讼成本小的,也会盯着金额低的去起诉。

好了,那么问题又来了。如果是同一家正规机构的钱,为什么低的被起诉了,高的却没有呢?这种情况要看逾期人的资质,要知道,起诉是有成本的,所以会事先调查这个人的信息,金额只是判断要不要起诉的一方面,还要看这个人是否有资产可执行,是否有稳定的工作和收入等。总之,这个中心思想还是要看他们费时费神的去起诉你之后值不值当,能不能回本。有车有房的,金额虽然低,但比起一穷二白,生病没工作的,回款率肯定高很多嘛。所以即便是同一家正规机构,也会出现金额低的被起诉,金额高的却没事这种情况。

这里给大家说一个真实案例:

有一位张先生,24岁,在事业单位上班,卡片逾期5W,月收入不高,扣除五险一金后也只有三千多!面对每月的账单他实在是无力偿还了,但是看着身边好多“过度消费”的朋友,逾期金额比自己高得多,有的甚至高出自己两三倍,除了被小崔骚扰好像也没什么实质性的东西,渐渐的他也觉得就算会被起诉,也应该是在他那些金额更高的朋友之后。但是当某一天,收到了法院的短信,他才知道原来对方真的把自己起诉了,然后连忙来咨询律师该怎么办!

这是因为他的工资虽然低,但是架不住稳定啊!你总不会为了几万就牺牲一个如此稳定的工作吧,为了保住这份工作,你自己解决不了,你的家人亲戚也会帮助你的!他的回款率,和他那些朋友不可同日而语,自然起诉他的概率就更大了!当然,不是说那些回款率低的就不起诉了,只是在对方的考量过程中,他们的顺序比较靠后而已,如果你逾期的是卡片方,不还钱是绝对不可能的。大家明白了吗?你在逾期路上遇到过什么问题呢?可以发出来讨论讨论!

关注美翎

带你上岸!

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

Python案例分析之客户信贷预测模型_通过一部分用信客户特征推断其余客户用信可能python_高羊羊羊羊羊杨的博客-CSDN博客

阅读提示

本文将通过逻辑回归算法实现用户信贷预测模型的建立,本次实验涉及到数据清洗、建模、预测三部分,希望各位读者能有所收获,感谢阅读。

一、项目解读

对年轻人来说,

还花呗

可以说是每个月必备的一项任务了,很有可能刚到手的工资还花呗就已经花去了大半。那么在这个快节奏的时代中,有时候我们需要支配一些资金去满足某些需求,但又因为囊中羞涩一时无法拿出太大的数额,为了解决这中尴尬的局面,信贷机构悄然产生了。

信贷业务又称为信贷资产或贷款业务,是商业银行最重要的资产业务,通过放款收回本金和利息,扣除成本后获得利润,所以信贷是商业银行的主要赢利手段。

由于放款脱离了银行的控制,不能按时收回本息的风险较大,所以对信贷应在遵守合同法和贷款通则的基础上,建立严格的贷款制度,其主要内容是:建立贷款关系,贷款申请,贷前调查,贷款审批及发放,贷后检查,贷款收回与展期,信贷制裁等制度。

1.1 逻辑回归算法

1.1.1 Logistic函数

Logistic回归模型中的因变量只有1和0(发生于不发生)两种。假设在p个独立自变量x1,x2…xp作用下,y取1的概率是p = P(y = 1|X)取0的概率是1-p,取1和取0的概率之比为

p 1 − p \frac{p}{1-p}

1

p

p

称为事件的优势比(odds),对odds取自然对数得Logistic变换

L o g i t ( p ) = l n ( p 1 − p ) 称 为 ① Logit(p) = ln(\frac{p}{1-p}) 称为①

L

o

g

i

t

(

p

)

=

l

n

(

1

p

p

)

令①=z,则

p = 1 1 + e z p = \frac{1}{1+e^{z}}

p

=

1

+

e

z

1

称为Logistic函数

如图:

1.1.2Logistic回归建模步骤

a、根据分析目的设置指标变量(因变量和自变量),然后收集数据,根据收集到的数据,对特征再次进行筛选

b、y取1的概率是p= P(y= 1|X), 取0概率是1-p。用

l n ( p 1 − p ) ln(\frac{p}{1-p})

l

n

(

1

p

p

)

和自变量列出线性回归方程,估计出模型中的回归系数

c、进行模型检验。模型有效性的检验指标有很多,最基本的有正确率,其次有混淆矩阵、ROC曲线、KS值等。

d、模型应用:输入自变量的取值,就可以得到预测变量的值,或者根据预测变量的值去控制自变量的取值。

实例:

年龄

教育

工龄

地址

收入

负债率

信用卡负债

其他负债

违约

41

3

17

12

176.00

9.30

11.36

5.01

1

27

1

10

6

31.00

17.30

1.36

4.00

0

需要数据集请私聊我

​ 利用Scikit-Learn对这个数据进行逻辑回归分析。首先进行特征筛选,特征筛选的方法有很多,主要包含在Scikit_Learn 的feature_ selection 库中,比较简单的有通过

F检验(f_ regression)

来给出各个特征的F值和p值,从而可以筛选变量(选择F值大的或者p值小的特征)。其次有

递归特征消除( Recursive Feature Elimination, RFE)

稳定性选择(StabilitySelection)

等比较新的方法。这里使用了稳定性选择方法中的

随机逻辑回归

进行特征筛选,然后利用筛选后的特征建立逻辑回归模型,输出平均正确率。

逻辑回归代码

import

pandas

as

pdfilename

=

'../data/bankloan.xls'

data

=

pd

.

read_excel

(

filename

)

x

=

data

.

iloc

[

:

,

:

8

]

.

as_matrix

(

)

y

=

data

.

iloc

[

:

,

8

]

.

as_matrix

(

)

from

sklearn

.

linear_model

import

LogisticRegression

as

LR

from

stability_selection

.

randomized_lasso

import

RandomizedLogisticRegression

as

RLRrlr

=

RLR

(

)

rlr

.

fit

(

x

,

y

)

rlr

.

get_support

(

)

print

(

u

'通过随机逻辑回归模型筛选特征结束。'

)

print

(

u

'有效特征为:%s'

%

','

.

join

(

data

.

columns

[

rlr

.

get_support

(

)

]

)

)

x

=

data

[

data

.

columns

[

rlr

.

get_support

(

)

]

]

.

as_matrix

(

)

lr

=

LR

(

)

lr

.

fit

(

x

,

y

)

print

(

u

'逻辑回归模型训练结束。'

)

print

(

u

'模型的平均正确率为:%s'

%

lr

.

score

(

x

,

y

)

)

结果:

通过随机逻辑回归模型筛选特征结束。有效特征为:工龄,地址,负债率,信用卡负债逻辑回归模型训练结束。模型的平均正确率为:

0.814285714286

1.2 客户逾期还款业务

在本文中,将通过对收集到的贷款机构数据集进行清洗与建模,预测用户是否具有还款能力并判断是否贷款给该用户,本文将从数据清洗、数据挖掘、数据建模三个方面进行一个小小的实战操作。

1.3 数据源内容解读

数据集是Lending Club平台产生借贷的业务数据,共有52个变量,39522条记录。

让我们先看一下数据集是什么样子

可以看到数据样本中有很多很多列

属性

,而每一列都代表什么

特征

呢?

这里我选取了一部分进行

汉化

而在我们真正进行建模的时候,并不是所有的属性都会用到,我们需要先对数据进行预处理。

1.4 Python主要数据预处理函数

在数据挖掘中,海量的原始数据中存在着大量不完整(有缺失值)、不一致、有异常的数据,严重影响到数据挖掘建模的执行效率,甚至可能导致挖掘结果的偏差,所以进行数据清洗就显得尤为重要,数据清洗完成后接着进行或者同时进行数据集成、转换、规约等一系列的处理,该过程就是数据预处理。数据预处理一方面是要提高数据的质量,另一方面是要让数据更好地适应特定的挖掘技术或工具。统计发现,在数据挖掘的过程中,数据预处理工作量占到了整个过程的60%。

数据预处理的主要内容包括

:数据清洗、数据集成、数据变换和数据规约

函数名

函数功能

所属拓展库

interpolate

一维、高维数据插值

Scipy

unique

去除数据中的重复元素,得到单值元素列表,它是对象的方法名

Pandas/Numpy

isnull

判断是否为空

Pandas

notnull

判断是否非空

Pandas

PCA

对指标变量矩阵进行主成分分析

Scikit-Learn

random

生成随机矩阵

Numpy

1.4.1 interpolate

功能:

interpolate是Scipy的一一个子库,包含了大量的插值函数,如拉格朗日插值、样条插值、高维插值等。使用前需要用from scipy.interpolate import *引入相应的插值函数,可以根据需要到官网查找对应的函数名。

使用格式:

f

=

scipy

.

interpolate

.

lagrange

(

x

,

y

)

​ 这里仅仅展示了一维数据的拉格朗日插值的命令,其中x, y为对应的自变量和因变量数据。插值完成后,可以通过f(a) 计算新的插值结果。类似的还有样条插值、多维数据插值等,此处不一一展示。

1.4.2 unique

**功能: ** 去除数据中的重复元素,得到单值元素列表。它既是Numpy库的一个函数(np.unique()),也是Series对象的一个方法。

使用格式:

np.unique(D) ,D是一维数据,可以是list、array、Series

D.unique(),D是Pandas的Series对象

实例:

求向量A中的单值元素,并返回相关索引

D

=

pd

.

Series

(

[

1

,

1

,

2

,

3

,

5

]

)

print

(

D

.

unique

(

)

)

print

(

np

.

unique

(

D

)

)

结果:

[

1

2

3

5

]

[

1

2

3

5

]

Process finished

with

exit code

0

1.4.3 isnull / notnull

功能:

判断每个元素是否空值 / 非空值

使用格式:

D.isnull()/ D.notnull()。这里的D要求是Series对象,返回一个布尔Series。可以通过D [ D.isnull()]或D[D.notnull()]找出D中的空值 / 非空值。

1.4.4andom

功能:

random是Numpy的一个子库(Python本身也自带了random,但Numpy的更加强大),可以用该库下的各种函数生成服从特定分布的随机矩阵,抽样时可使用。

使用格式

np.random.randn(k, m, n,…生成一个k * m * n *… 随机矩阵,其元素均匀分布在区间(0,1)上

np.random.randn(k, m, n…)_.生成一个k * m * n * …随机矩阵,其元素服从标准正态分布

1.4.5 PCA

功能:

对指标变量矩阵进行主成分分析,使用前需要用

from sklearn.decomposition import PCA

引入该函数。

使用格式:

model = PCA()。 注意,Scikit-Learn 下的PCA是一个建模式的对象,也就是说,一般的流程是建模,然后是训练model.fit(D),D为要进行主成分分析的数据矩阵,训练结束后获取模型的参如.components_获取特征向量,以及.explained_ variance. _ratio_获取各个属性的贡献率等。

实例:

使用PCA()对一个10 * 4 维的随机矩阵进行主成分分析

from

sklearn

.

decomposition

import

PCAD

=

np

.

random

.

randn

(

10

,

4

)

pca

=

PCA

(

)

pca

.

fit

(

D

)

PCA

(

copy

=

True

,

n_components

=

None

,

whiten

=

False

)

print

(

pca

.

components_

)

print

(

"*"

*

50

)

print

(

pca

.

explained_variance_ratio_

)

结果:

[

[

-

0.73391691

0.22922579

-

0.13039917

0.62595332

]

[

-

0.41771778

0.57241446

-

0.02724733

-

0.70506108

]

[

0.22012336

0.49807219

0.80277934

0.24293029

]

[

-

0.48828633

-

0.60968952

0.58120475

-

0.22815825

]

]

**

**

**

**

**

**

**

**

**

**

**

**

**

**

**

**

**

**

**

**

**

**

**

**

**

[

0.50297117

0.28709267

0.14575757

0.06417859

]

Process finished

with

exit code

0

二、数据预处理

首先,去掉一些明显没用的特征,如

desc

url

,并将剩下特征保存到一个新的csv文件中。(也可以使用

replace()

参数)

2.1 调用warnings包,屏蔽报红

import

warningswarnings

.

filterwarnings

(

'ignore'

)

2.2 筛选特征值

分析数据集,显示数据标签,挑选我们不需要的特征

这里先做一个约定,2万行数据中,如果空白值超过一半,则剔除掉这些列

thresh = half_count

:剔除

import

pandas

as

pdloans_2020

=

pd

.

read_csv

(

'LoanStats3a.csv'

,

skiprows

=

1

)

half_count

=

len

(

loans_2020

)

/

2

loans_2020

=

loans_2020

.

dropna

(

thresh

=

half_count

,

axis

=

1

)

loans_2020

=

loans_2020

.

drop

(

[

'desc'

,

'url'

]

,

axis

=

1

)

loans_2020

.

to_csv

(

'loans_2020.csv'

,

index

=

False

)

这里我们对处理好的数据进行展示

import

pandas

as

pdloans_2020

=

pd

.

read_csv

(

"loans_2020.csv"

)

print

(

"数据展示:第一行 \n"

,

loans_2020

.

iloc

[

0

]

)

数据展示:第一行 id 1077501member_id 1.2966e+06loan_amnt 5000funded_amnt 5000funded_amnt_inv 4975term 36 monthsint_rate 10.65%installment 162.87grade Bsub_grade B2emp_title NaNemp_length 10+ yearshome_ownership RENTannual_inc 24000verification_status Verifiedissue_d Dec-11loan_status Fully Paidpymnt_plan npurpose credit_cardtitle Computerzip_code 860xxaddr_state AZdti 27.65delinq_2yrs 0earliest_cr_line Jan-85inq_last_6mths 1open_acc 3pub_rec 0revol_bal 13648revol_util 83.70%total_acc 9initial_list_status fout_prncp 0out_prncp_inv 0total_pymnt 5863.16total_pymnt_inv 5833.84total_rec_prncp 5000total_rec_int 863.16total_rec_late_fee 0recoveries 0collection_recovery_fee 0last_pymnt_d Jan-15last_pymnt_amnt 171.62last_credit_pull_d Nov-16collections_12_mths_ex_med 0policy_code 1application_type INDIVIDUALacc_now_delinq 0chargeoff_within_12_mths 0delinq_amnt 0pub_rec_bankruptcies 0tax_liens 0Name: 0, dtype: object

shape[1]

代表有多少列 ,

shape[0]

代表有多少行

print

(

"原始列数={}"

.

format

(

loans_2020

.

shape

[

1

]

)

)

原始列数= 52

通常来说,样本中的

id

member_id

属性对银行评定是否放贷并

没有任何影响

,这只是用户所特有的标识;而

funded_amnt

(期望贷款的数目)和

funded_amnt_inv

(实际贷到的数目)显然与我们要做的预测也

没什么关系

在判断一个特征值是否有用时要结合很多实际情况进行分析

。这里不做过多讨论,为了实验方便我们选择舍弃这些属性列。

'''id:用户ID#member_id:会员编号funded_amnt:承诺给该贷款的总金额funded_amnt_inv:投资者为该贷款承诺的总金额grade:贷款等级。贷款利率越高,则等级越高sub_grade:贷款子等级emp_title:工作名称issue_d:贷款月份'''

loans_2020

=

loans_2020

.

drop

(

[

"id"

,

"member_id"

,

"funded_amnt"

,

"funded_amnt_inv"

,

"grade"

,

"sub_grade"

,

"emp_title"

,

"issue_d"

]

,

axis

=

1

)

在这里我们看一下用户

当前贷款的状态

loans_2020

[

'loan_status'

]

0 Fully Paid1 Charged Off2 Fully Paid3 Fully Paid4 Current ... 39530 Fully Paid39531 NaN39532 NaN39533 NaN39534 NaNName: loan_status, Length: 39535, dtype: object

继续剔除不需要的属性列

loans_2020

=

loans_2020

.

drop

(

[

"zip_code"

,

"out_prncp"

,

"out_prncp_inv"

,

"total_pymnt"

,

"total_pymnt_inv"

,

"total_rec_prncp"

]

,

axis

=

1

)

loans_2020

=

loans_2020

.

drop

(

[

"total_rec_int"

,

"total_rec_late_fee"

,

"recoveries"

,

"collection_recovery_fee"

,

"last_pymnt_d"

,

"last_pymnt_amnt"

]

,

axis

=

1

)

print

(

loans_2020

.

iloc

[

0

]

)

loan_amnt 5000term 36 monthsint_rate 10.65%installment 162.87emp_length 10+ yearshome_ownership RENTannual_inc 24000verification_status Verifiedloan_status Fully Paidpymnt_plan npurpose credit_cardtitle Computeraddr_state AZdti 27.65delinq_2yrs 0earliest_cr_line Jan-85inq_last_6mths 1open_acc 3pub_rec 0revol_bal 13648revol_util 83.70%total_acc 9initial_list_status flast_credit_pull_d Nov-16collections_12_mths_ex_med 0policy_code 1application_type INDIVIDUALacc_now_delinq 0chargeoff_within_12_mths 0delinq_amnt 0pub_rec_bankruptcies 0tax_liens 0Name: 0, dtype: object

那么经过初步筛选后,剩下了多少特征列呢?

print

(

"现存列数 = "

,

loans_2020

.

shape

[

1

]

)

现存列数 = 32

确定当前贷款状态(label值)

2.3 LabelEncoder 和 OneHotEncoder

在进行Python数据处理的时候,我们想要将繁杂的数据特征变成简单、容易识别的编码,Python为我们提供了两个非常好用的方法。

通俗来说

LabelEncoder

是对不连续的数字或者文本进行编号

from

sklearn

.

preprocessing

import

LabelEncoderle

=

LabelEncoder

(

)

le

.

fit

(

[

1

,

5

,

67

,

100

]

)

le

.

transform

(

[

1

,

1

,

100

,

67

,

5

]

)

print

(

le

.

transform

(

[

1

,

1

,

100

,

67

,

5

]

)

)

OneHotEncoder

用于将表示分类的数据扩维

from

sklearn

.

preprocessing

import

OneHotEncoderohe

=

OneHotEncoder

(

)

ohe

.

fit

(

[

[

1

]

,

[

2

]

,

[

3

]

,

[

4

]

]

)

ohe

.

transform

(

(

[

2

]

,

[

3

]

,

[

1

]

,

[

4

]

)

)

.

toarray

(

)

print

(

ohe

.

transform

(

(

[

2

]

,

[

3

]

,

[

1

]

,

[

4

]

)

)

.

toarray

(

)

)

[

[

0

.

1

.

0

.

0

.

]

[

0

.

0

.

1

.

0

.

]

[

1

.

0

.

0

.

0

.

]

[

0

.

0

.

0

.

1

.

]

]

那么对我们拿到的数据集该如何处理呢?

print

(

loans_2020

[

'loan_status'

]

.

value_counts

(

)

)

'''Fully Paid:批准了客户的贷款,可看做 1Charged Off:没有批准了客户的贷款,可看做 0Late (16-30 days) :延期了16-30 daysLate (31-120 days):延期了31-120 days ,所以这些都不确定的属性,相当于“取保候审”'''

Fully Paid 33693Charged Off 5612Current 201Late (31-120 days) 10In Grace Period 9Late (16-30 days) 5Default 1Name: loan_status, dtype: int64

二分类

loans_2020

=

loans_2020

[

(

loans_2020

[

'loan_status'

]

==

"Fully Paid"

)

|

(

loans_2020

[

'loan_status'

]

==

"Charged Off"

)

]

status_replace

=

{

"loan_status"

:

{

"Fully Paid"

:

1

,

"Charged Off"

:

0

,

}

}

loans_2020

=

loans_2020

.

replace

(

status_replace

)

在进行编码后,数据变成了这个样子

loans_2020

[

'loan_status'

]

0 11 02 13 15 1 ..39526 139527 139528 139529 139530 1Name: loan_status, Length: 39305, dtype: int64

2.4 去掉特征中只有一种属性的列

orig_columns

=

loans_2020

.

columns drop_columns

=

[

]

for

col

in

orig_columns

:

col_series

=

loans_2020

[

col

]

.

dropna

(

)

.

unique

(

)

if

len

(

col_series

)

==

1

:

drop_columns

.

append

(

col

)

loans_2020

=

loans_2020

.

drop

(

drop_columns

,

axis

=

1

)

print

(

drop_columns

)

print

(

"--------------------------------------------"

)

print

(

loans_2020

.

shape

)

loans_2020

.

to_csv

(

'filtered_loans_2020.csv'

,

index

=

False

这时只剩下39305行,24列数据了

['initial_list_status', 'collections_12_mths_ex_med', 'policy_code', 'application_type', 'acc_now_delinq', 'chargeoff_within_12_mths', 'delinq_amnt', 'tax_liens']--------------------------------------------(39305, 24)

注:

当我们筛选出特征和标签后,就可以丢给

scikit-learn

了吗?

当然是不行的,还需要做缺失值、字符值、标点符号、%号、str等值得处理。

2.5 处理缺失值

import

pandas

as

pdloans

=

pd

.

read_csv

(

'filtered_loans_2020.csv'

)

null_counts

=

loans

.

isnull

(

)

.

sum

(

)

print

(

null_counts

)

loan_amnt 0term 0int_rate 0installment 0emp_length 1073home_ownership 0annual_inc 0verification_status 0loan_status 0pymnt_plan 0purpose 0title 11addr_state 0dti 0delinq_2yrs 0earliest_cr_line 0inq_last_6mths 0open_acc 0pub_rec 0revol_bal 0revol_util 50total_acc 0last_credit_pull_d 1pub_rec_bankruptcies 449dtype: int64

从统计出的结果可以看出

title

revol_util

相对于数据总量来说较少,可以直接去掉缺失值所在的行。

pub_rec_bankruptcies

中的缺失值较多,说明该数据统计的情况较差,在本文中直接将此特征删除即可。

loans

=

loans

.

drop

(

"pub_rec_bankruptcies"

,

axis

=

1

)

loans

=

loans

.

dropna

(

axis

=

0

)

print

(

loans

.

dtypes

.

value_counts

(

)

)

删除后,统计各类型是特征的数目

object 12float64 10int64 1dtype: int64

2.6数据类型的转换

由于

sk-learn

库不接受字符型的数据,所以还需将上面特征中12个字符型的数据进行处理。

object_columns_df

=

loans

.

select_dtypes

(

include

=

[

"object"

]

)

print

(

object_columns_df

.

iloc

[

0

]

)

处理思路

term

:分期多少个月

int_rate

:利息,10.65%,后面还要去掉%

emp_length

:超过10年的看做是10,9年看做是9…

home_ownership

:房屋所有权,是租的、自己的、还是抵押掉了,使用用0 1 2来代替

term 36 monthsint_rate 10.65%emp_length 10+ yearshome_ownership RENTverification_status Verifiedpymnt_plan npurpose credit_cardtitle Computeraddr_state AZearliest_cr_line Jan-85revol_util 83.70%last_credit_pull_d Nov-16Name: 0, dtype: object

'''查看指定标签的属性,并记数home_ownership:房屋所有权verification_status:身份保持证明emp_length:工作时长term:贷款分期的时间addr_state:地址邮编'''

cols

=

[

'home_ownership'

,

'verification_status'

,

'emp_length'

,

'term'

,

'addr_state'

]

for

c

in

cols

:

print

(

loans

[

c

]

.

value_counts

(

)

)

RENT 18237MORTGAGE 17035OWN 2805OTHER 96NONE 1Name: home_ownership, dtype: int64Not Verified 16182Verified 12251Source Verified 9741Name: verification_status, dtype: int6410+ years 8794< 1 year 44922 years 43393 years 40524 years 33975 years 32621 year 31826 years 22017 years 17478 years 14639 years 1245Name: emp_length, dtype: int64 36 months 27980 60 months 10194Name: term, dtype: int64CA 6876NY 3644FL 2739TX 2657NJ 1799IL 1478PA 1470VA 1355GA 1342MA 1278OH 1176MD 1019AZ 824WA 788CO 758NC 739CT 725MI 688MO 654MN 589NV 477SC 457OR 431WI 429AL 424LA 422KY 320OK 292KS 257UT 248AR 233DC 211RI 196NM 180HI 168WV 167NH 160DE 109MT 78WY 78AK 77SD 61VT 54MS 19TN 16ID 6IA 5NE 1Name: addr_state, dtype: int64

显示

purpose

title

属性

print

(

loans

[

"purpose"

]

.

value_counts

(

)

)

print

(

"------------------------------------------------"

)

print

(

loans

[

"title"

]

.

value_counts

(

)

)

debt_consolidation 18057credit_card 4927other 3761home_improvement 2846major_purchase 2103small_business 1745car 1489wedding 924medical 665moving 551house 364vacation 347educational 300renewable_energy 95Name: purpose, dtype: int64------------------------------------------------Debt Consolidation 2122Debt Consolidation Loan 1670Personal Loan 625Consolidation 502debt consolidation 483 ... Unexpected Legal Fees-Short Term 1Payoff The cards 1increasing membership 1Silver products 1Getting back on the road!! 1Name: title, Length: 18933, dtype: int64

将工作年限

LabelEncoder

'''jemp_length设置为字典,emp_length当做key ,value里还是字典"10+ years": 10..."9 years" : 9......调用replace函数进行替换操作在利息这列,有符号%,使用astype()处理'''

mapping_dict

=

{

"emp_length"

:

{

"10+ years"

:

10

,

"9 years"

:

9

,

"8 years"

:

8

,

"7 years"

:

7

,

"6 years"

:

6

,

"5 years"

:

5

,

"4 years"

:

4

,

"3 years"

:

3

,

"2 years"

:

2

,

"1 year"

:

1

,

"< 1 year"

:

0

,

"n/a"

:

0

}

}

loans

=

loans

.

drop

(

[

"last_credit_pull_d"

,

"earliest_cr_line"

,

"addr_state"

,

"title"

]

,

axis

=

1

)

loans

[

"int_rate"

]

=

loans

[

"int_rate"

]

.

str

.

rstrip

(

"%"

)

.

astype

(

"float"

)

loans

[

"revol_util"

]

=

loans

[

"revol_util"

]

.

str

.

rstrip

(

"%"

)

.

astype

(

"float"

)

loans

=

loans

.

replace

(

mapping_dict

)

mapping_dict

{'emp_length': {'10+ years': 10, '9 years': 9, '8 years': 8, '7 years': 7, '6 years': 6, '5 years': 5, '4 years': 4, '3 years': 3, '2 years': 2, '1 year': 1, '< 1 year': 0, 'n/a': 0}}

剩余的其他字符型特征,此处选择使用pandas的get_dummies()函数,直接映射为数值型。

print

(

loans

)

loan_amnt term int_rate installment emp_length \0 5000.0 36 months 10.65 162.87 10 1 2500.0 60 months 15.27 59.83 0 2 2400.0 36 months 15.96 84.33 10 3 10000.0 36 months 13.49 339.31 10 4 5000.0 36 months 7.90 156.46 3 ... ... ... ... ... ... 39300 12000.0 36 months 9.33 383.45 2 39301 4000.0 36 months 8.07 125.48 4 39302 9000.0 36 months 10.59 292.91 1 39303 10000.0 36 months 8.38 315.12 0 39304 12000.0 36 months 9.96 386.99 10 home_ownership annual_inc verification_status loan_status pymnt_plan \0 RENT 24000.0 Verified 1 n 1 RENT 30000.0 Source Verified 0 n 2 RENT 12252.0 Not Verified 1 n 3 RENT 49200.0 Source Verified 1 n 4 RENT 36000.0 Source Verified 1 n ... ... ... ... ... ... 39300 RENT 68640.0 Not Verified 1 n 39301 RENT 21600.0 Not Verified 1 n 39302 RENT 25920.0 Not Verified 1 n 39303 RENT 107000.0 Not Verified 1 n 39304 MORTGAGE 100000.0 Not Verified 1 n purpose dti delinq_2yrs inq_last_6mths open_acc \0 credit_card 27.65 0.0 1.0 3.0 1 car 1.00 0.0 5.0 3.0 2 small_business 8.72 0.0 2.0 2.0 3 other 20.00 0.0 1.0 10.0 4 wedding 11.20 0.0 3.0 9.0 ... ... ... ... ... ... 39300 debt_consolidation 7.47 2.0 0.0 8.0 39301 debt_consolidation 10.33 0.0 1.0 6.0 39302 major_purchase 5.56 0.0 2.0 7.0 39303 small_business 2.28 0.0 2.0 4.0 39304 debt_consolidation 8.17 0.0 2.0 14.0 pub_rec revol_bal revol_util total_acc 0 0.0 13648.0 83.7 9.0 1 0.0 1687.0 9.4 4.0 2 0.0 2956.0 98.5 10.0 3 0.0 5598.0 21.0 37.0 4 0.0 7963.0 28.3 12.0 ... ... ... ... ... 39300 0.0 11370.0 41.6 22.0 39301 0.0 3737.0 55.8 11.0 39302 0.0 6353.0 39.5 8.0 39303 0.0 15043.0 65.2 25.0 39304 0.0 25413.0 45.2 26.0 [38174 rows x 19 columns]

查看指定标签的属性,并记数

'''home_ownership:房屋所有权verification_status:身份保持证明emp_length:客户公司名称purpose:贷款的意图term:贷款分期的时间'''

cat_columns

=

[

"home_ownership"

,

"verification_status"

,

"emp_length"

,

"purpose"

,

"term"

]

dummy_df

=

pd

.

get_dummies

(

loans

[

cat_columns

]

)

loans

=

pd

.

concat

(

[

loans

,

dummy_df

]

,

axis

=

1

)

loans

=

loans

.

drop

(

cat_columns

,

axis

=

1

)

loans

=

loans

.

drop

(

"pymnt_plan"

,

axis

=

1

)

loans

.

to_csv

(

'cleaned_loans_2020.csv'

,

index

=

False

)

总结:

什么时候用OneHotEncoder独热编码和LabelEncoder标签编码?

特征的属性小于等于3 ,用OneHotEncoder,比如:天气、性别 ,属于无序特征

特征的属性大于3,用LabelEncoder,比如:星期属于有序型

数据类型转换

import

pandas

as

pdloans

=

pd

.

read_csv

(

"cleaned_loans_2020.csv"

)

print

(

loans

.

info

(

)

)

<class 'pandas.core.frame.DataFrame'>RangeIndex: 38174 entries, 0 to 38173Data columns (total 37 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 loan_amnt 38174 non-null float64 1 int_rate 38174 non-null float64 2 installment 38174 non-null float64 3 annual_inc 38174 non-null float64 4 loan_status 38174 non-null int64 5 dti 38174 non-null float64 6 delinq_2yrs 38174 non-null float64 7 inq_last_6mths 38174 non-null float64 8 open_acc 38174 non-null float64 9 pub_rec 38174 non-null float64 10 revol_bal 38174 non-null float64 11 revol_util 38174 non-null float64 12 total_acc 38174 non-null float64 13 home_ownership_MORTGAGE 38174 non-null int64 14 home_ownership_NONE 38174 non-null int64 15 home_ownership_OTHER 38174 non-null int64 16 home_ownership_OWN 38174 non-null int64 17 home_ownership_RENT 38174 non-null int64 18 verification_status_Not Verified 38174 non-null int64 19 verification_status_Source Verified 38174 non-null int64 20 verification_status_Verified 38174 non-null int64 21 purpose_car 38174 non-null int64 22 purpose_credit_card 38174 non-null int64 23 purpose_debt_consolidation 38174 non-null int64 24 purpose_educational 38174 non-null int64 25 purpose_home_improvement 38174 non-null int64 26 purpose_house 38174 non-null int64 27 purpose_major_purchase 38174 non-null int64 28 purpose_medical 38174 non-null int64 29 purpose_moving 38174 non-null int64 30 purpose_other 38174 non-null int64 31 purpose_renewable_energy 38174 non-null int64 32 purpose_small_business 38174 non-null int64 33 purpose_vacation 38174 non-null int64 34 purpose_wedding 38174 non-null int64 35 term_ 36 months 38174 non-null int64 36 term_ 60 months 38174 non-null int64 dtypes: float64(12), int64(25)memory usage: 10.8 MBNone

三、模型训练

前面花费了大量的时间在进行数据处理,这足以说明在机器学习中数据准备的工作有多重要,有了好的数据才能预测出好的分类结果,

对于二分类问题,一般情况下,首选逻辑回归。

首先定义模型效果的评判标准。根据贷款行业的实际情况,在这里我们

假设将钱借给了没有还款能力的人,结果损失一千

将钱借给了有偿还能力的人,从每笔中赚0.1的利润

,而其余情况收益为零,就相当于预测对十个人才顶上预测错一个人的收益,所以精度不再适用于此模型,为了实现利润最大化,不仅要求模型预测recall率较高,同时是需要要让

fall-out

率较低,故这里采用两个指标

TPR(true positive rate)

FPR(false positive rate)

from

sklearn

.

linear_model

import

LogisticRegression lr

=

LogisticRegression

(

)

cols

=

loans

.

columns train_cols

=

cols

.

drop

(

"loan_status"

)

features

=

loans

[

train_cols

]

target

=

loans

[

"loan_status"

]

lr

.

fit

(

features

,

target

)

predictions

=

lr

.

predict

(

features

)

3.1 查看预测结果

predictions

[

:

10

]

array

(

[

1

,

1

,

1

,

1

,

1

,

1

,

1

,

1

,

1

,

1

]

,

dtype

=

int64

)

lr

.

predict_proba

(

features

)

array

(

[

[

0.23940129

,

0.76059871

]

,

[

0.35607142

,

0.64392858

]

,

[

0.32106074

,

0.67893926

]

,

.

.

.

,

[

0.30770809

,

0.69229191

]

,

[

0.10258821

,

0.89741179

]

,

[

0.09494366

,

0.90505634

]

]

)

3.2 逻辑回归的超参数

lr

LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True, intercept_scaling=1, l1_ratio=None, max_iter=100, multi_class='auto', n_jobs=None, penalty='l2', random_state=None, solver='lbfgs', tol=0.0001, verbose=0, warm_start=False)

3.3 分析需求

目的是赚取有能力偿还贷款的客户的利息

第一个实际值为0,客户不会还钱,模型预测客户能还钱,为1 ,假设系统贷给了客户1000块钱,但是一分都没还,说明预测错了为阴性,赔了1000块钱

第二个实际值为1,客户有偿还能力,模型预测客户有能力偿还,就挣了客户的利息钱,1000*0.1 =100块钱

第三个实际值为0,本来客户是不还钱的,模型预测不还钱,并且没有贷款给他

第四个客户能还钱,模型预测客户不能还 ,没有贷款给他

3.4 建立混淆矩阵

import

pandas

as

pd

print

(

"----------------------------------------"

)

fp_filter

=

(

predictions

==

1

)

&

(

loans

[

"loan_status"

]

==

0

)

fp

=

len

(

predictions

[

fp_filter

]

)

print

(

fp

)

print

(

"----------------------------------------"

)

tp_filter

=

(

predictions

==

1

)

&

(

loans

[

"loan_status"

]

==

1

)

tp

=

len

(

predictions

[

tp_filter

]

)

print

(

tp

)

print

(

"----------------------------------------"

)

fn_filter

=

(

predictions

==

0

)

&

(

loans

[

"loan_status"

]

==

1

)

fn

=

len

(

predictions

[

fn_filter

]

)

print

(

fn

)

print

(

"----------------------------------------"

)

tn_filter

=

(

predictions

==

0

)

&

(

loans

[

"loan_status"

]

==

0

)

tn

=

len

(

predictions

[

tn_filter

]

)

print

(

"----------------------------------------"

)

print

(

tn

)

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

5355

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

32786

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

23

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

10

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

-

这里有个问题:

最终拿什么衡量指标来评价模型?

这个数据集后续观察是不平衡的 ,借钱的有6个,不借钱的有1个,借钱的样本本来就多,不借钱的样本本来就少,相当于7个人来了,有6个人借给他了(定为1),有1个人没借给他(定为0),7个样本的错误率为1/7 ,准确率为6/7 ,用”精度“衡量的时候看一下图例:

第一个实际值为0,没有偿还能力,模型预测客户为1 ,代表不能还,赔1000块钱

后面的实际值为1,代表有偿还能力,模型借给他1000块钱,挣了个利息钱100块

最终-1000 + 600 = -400 用”精度“来衡量最终还是会赔钱的,因为数据集能还钱的样本很多,显然这样是不合理的,所以就不考虑”精度“了。

所以这里我们建立混淆矩阵

from

sklearn

.

linear_model

import

LogisticRegression

from

sklearn

.

model_selection

import

cross_val_predictlr

=

LogisticRegression

(

)

predictions

=

cross_val_predict

(

lr

,

features

,

target

,

cv

=

10

)

predictions

=

pd

.

Series

(

predictions

)

print

(

predictions

[

:

1000

]

)

0 11 12 13 14 1 ..995 1996 1997 1998 1999 1Length: 1000, dtype: int64

fp_filter

=

(

predictions

==

1

)

&

(

loans

[

"loan_status"

]

==

0

)

fp

=

len

(

predictions

[

fp_filter

]

)

tp_filter

=

(

predictions

==

1

)

&

(

loans

[

"loan_status"

]

==

1

)

tp

=

len

(

predictions

[

tp_filter

]

)

fn_filter

=

(

predictions

==

0

)

&

(

loans

[

"loan_status"

]

==

1

)

fn

=

len

(

predictions

[

fn_filter

]

)

tn_filter

=

(

predictions

==

0

)

&

(

loans

[

"loan_status"

]

==

0

)

tn

=

len

(

predictions

[

tn_filter

]

)

T P R = t r u e p o s i t i v e s f a l s e p o s i t i v e s + t r u e p o s i t i v e s TPR = \frac{truepositives}{falsepositives + truepositives}

T

P

R

=

f

a

l

s

e

p

o

s

i

t

i

v

e

s

+

t

r

u

e

p

o

s

i

t

i

v

e

s

t

r

u

e

p

o

s

i

t

i

v

e

s

F P R = f a l s e p o s i t i v e s f a l s e p o s i t i v e s + t r u e p o s i t i v e s FPR = \frac{falsepositives}{falsepositives + truepositives}

F

P

R

=

f

a

l

s

e

p

o

s

i

t

i

v

e

s

+

t

r

u

e

p

o

s

i

t

i

v

e

s

f

a

l

s

e

p

o

s

i

t

i

v

e

s

真正率TPR:

是指客户的实际值为1,有偿还能力,模型预测也为1,说明这些客户群体越来越多,挣的利息也越来越多(

我们想让TRP越高越好

本质上期望TPR越高越好,FPR越低越好

tpr

=

tp

/

float

(

(

tp

+

fn

)

)

fpr

=

fp

/

float

(

(

fp

+

tn

)

)

print

(

tpr

)

print

(

fpr

)

print

(

predictions

[

:

20

]

)

0.99911609619311770.9986952469711090 11 12 13 14 15 16 17 18 19 110 111 112 113 114 115 116 117 118 119 1dtype: int64

从得到的结果中发现前20个人几乎都是有能力还款且贷款给他们了,说明来一个人基本都会判断为可以借钱,那显然模型就完全没有分类的意义。

这时候我们就要考虑一个重要的问题了:

权重

为什么会出现这种情况?

问题就出在了前面的数据集中,比如说数据是6:1,绝大多数是1,小部分是0,样本不均衡的情况下,导致分类器错误的认为把所有的样本预测为1,因为负样本少,我们需要进行

“数据增强”

对数据来说,一部分是6份,另一部分是1份,把6份的权重设置为1,把1份的权重设置为6,设置权重项来进行衡量,把不均衡的样本变得均衡,加了权重项,让正样本对结果的影响小一些

3.5 考虑权重后使用逻辑回归训练

from

sklearn

.

linear_model

import

LogisticRegression

from

sklearn

.

model_selection

import

cross_val_predict

"""class_weight:可以调整正反样本的权重balanced:希望正负样本平衡一些的"""

lr

=

LogisticRegression

(

class_weight

=

"balanced"

)

predictions

=

cross_val_predict

(

lr

,

features

,

target

,

cv

=

10

)

predictions

=

pd

.

Series

(

predictions

)

fp_filter

=

(

predictions

==

1

)

&

(

loans

[

"loan_status"

]

==

0

)

fp

=

len

(

predictions

[

fp_filter

]

)

tp_filter

=

(

predictions

==

1

)

&

(

loans

[

"loan_status"

]

==

1

)

tp

=

len

(

predictions

[

tp_filter

]

)

fn_filter

=

(

predictions

==

0

)

&

(

loans

[

"loan_status"

]

==

1

)

fn

=

len

(

predictions

[

fn_filter

]

)

tn_filter

=

(

predictions

==

0

)

&

(

loans

[

"loan_status"

]

==

0

)

tn

=

len

(

predictions

[

tn_filter

]

)

tpr

=

tp

/

float

(

(

tp

+

fn

)

)

fpr

=

fp

/

float

(

(

fp

+

tn

)

)

print

(

tpr

)

print

(

)

print

(

fpr

)

print

(

)

print

(

predictions

[

:

20

]

)

0.5273248194093084 #真正率0.33401677539608576 #假正率0 01 12 03 14 15 06 07 08 09 110 111 012 013 114 015 016 117 118 119 0dtype: int64

3.6 自定义权重后使用逻辑回归训练

from

sklearn

.

linear_model

import

LogisticRegression

from

sklearn

.

model_selection

import

cross_val_predict

"""权重项可以自己定义的0代表5倍的1代表10倍的"""

penalty

=

{

0

:

5

,

1

:

1

}

lr

=

LogisticRegression

(

class_weight

=

penalty

)

kf

=

10

predictions

=

cross_val_predict

(

lr

,

features

,

target

,

cv

=

kf

)

predictions

=

pd

.

Series

(

predictions

)

fp_filter

=

(

predictions

==

1

)

&

(

loans

[

"loan_status"

]

==

0

)

fp

=

len

(

predictions

[

fp_filter

]

)

tp_filter

=

(

predictions

==

1

)

&

(

loans

[

"loan_status"

]

==

1

)

tp

=

len

(

predictions

[

tp_filter

]

)

fn_filter

=

(

predictions

==

0

)

&

(

loans

[

"loan_status"

]

==

1

)

fn

=

len

(

predictions

[

fn_filter

]

)

tn_filter

=

(

predictions

==

0

)

&

(

loans

[

"loan_status"

]

==

0

)

tn

=

len

(

predictions

[

tn_filter

]

)

tpr

=

tp

/

float

(

(

tp

+

fn

)

)

fpr

=

fp

/

float

(

(

fp

+

tn

)

)

print

(

tpr

)

print

(

)

print

(

fpr

)

0.7041360602273766 # 真正率0.5237651444547996 # 假正率

四、总结

为什么会出现上面极其离谱的现象呢?

这是由于我们的样本是很不均衡的,这就容易导致我们构建的分类器把所有样本都归为样本量较大的那一个类。解决的方法有很多,其中一个是进行数据增强,就是把少的样本增多,但是要添加的数据要么是收集的,要么是自己造的,所以这项工作还是挺难的。所以将考虑权重,将少的样本的权重增大,期望模型能够达到比较均衡的状态。

对上述模型的预测结果进行简单的分析,发现错误率和正确率都达到99.9%,错误率太高,通过观察预测结果发现,模型几乎将所有的样本都判断为正例,通过对原始数据的了解,分析造成该现象的原因是由于政府样本数量相差太大,即样本不均衡造成模型对正例样本有所偏重,这里

采用对样本添加权重值

的方式进行调整,首先采用默认的均衡调整。

本文中的案例不是着重给出一个正确率的预测模型,只是给出使用机器学习建模的一般流程。

分为两大部分

数据处理和模型学习

第一部分需要大量的街舞知识对原始数据进行清理及特征提取

第二部分模型学习,涉及长时间的模型参数调整,调整方向和策略需要根据经验来灵活调整。

当模型效果不理想时,可以考虑的调整策略:

1、调节正负样本的权重参数。

2、更换模型算法。

3、同时几个使用模型进行预测,然后取去测的最终结果。

4、使用原数据,生成新特征。

5、调整模型参数

★至此,本文已经将客户贷款预测案例简单讲解完毕,希望各位读者能从文中真正的学到一些东西,最重要的还是面对不同案例时候灵活的应用所知所学,感谢阅读!

安全验证 - 知乎

进入知乎

知乎 - 有问题,就会有答案

系统监测到您的网络环境存在异常风险,为保证您的正常访问,请输入验证码进行验证。

开始验证

贷后催收中的风险联动管控指标 - 知乎

在番茄风控大数据之前的文章中,之前跟大家介绍过催收相关内容:

催收小词典,助你轻松讨回债务

今天文章会再跟大家介绍在这些催收指标中,哪些指标是可以反馈到贷前贷中风控环节的。在策略整体优化流程而言,数据是流动的,策略也应该是连贯、联动的。贷前策略、贷中策略、贷后策略,虽然在风险流程上是割裂的,但在风险而言却应该是整体连贯的整体,以上我们称之为风险指标的联动。此次文章我们将介绍贷后哪些指标,可以跟风险一起联动管控。

本次文章分两部分:

第一部分:参考之前的内容,给大家做一下贷后催收的相关科普;

第二部分:是在这些指标中,介绍跟风险联动最相关的内容

PART1:贷后知识普及

一.基本催收名词解释

Flow Rate

迁移率就是在贷后资产评估里最重要的报表了,比如计算M0到M1的迁徙率,公式就是:分子(M1状态下的在贷余额)/分母(上月M0状态下的在贷余额)

具体的报表是长这样的:

(某公司产品的资产表现)

PTP

通过电话催收,客户承诺在一定期限内归还一定数额的欠款,称之为承诺还款。

用来计算客户下p的数据,用来衡量客户承诺还款的数据,单位是次数。这个指标是很重要的一个指标,因为经常下p的客户,起码还是有还款意愿的

kptp

客户承诺还款,并不代表客户就一定会还款,还要看客户还款的时间是否真正有还款,于是这个指标是很重要的一个指标,这个也是经常在评分卡里建模的一个重要变量

bp

客户承诺还款后,实际还还不了款的次数,这个指标也是非常重要的,用来衡量,计算公式是PTP和KPTP之差。正常情况下,该数会是正数,但是也会出现负数的情况,比如kptp的次数会比下p的次数多。举个栗子,比如承诺还款1000元,实际还了三次,每次还款100元,这样计算下来BP是负2,这种出现负数的一般说是客户还款意愿好,但是客户还款能力不足。

in_ptp

电话催收,客户承诺在一定期限内归还一定数额的欠款,该周期内统称P期。一般的公司把p期定为t+3,也就是说在下P的时间里3天内有效。

v_ptp

指有效的PTP,即客户承诺还款后,处于该周期内的P均为有效(Valid PTP)。

DPD

即合同的最早的一笔分期的逾期日期到现在的时间间隔(Days past due)。

CPD

主要跟DPD有相对,一般的公司会把逾期金额欠款金额大于50元才会加入催收的名单里,把这块叫CPD

M1 M2 M3 DPD90+

逾期阶段,以30天为一个单位。

M1:DPD1-30;

M2:DPD31-60;

M3:DPD61-90(有些公司会把M1为DPD1-29,M2为DPP30-59,M3为DPD60-89)

DPD90+即为坏账,之后可以进行核销了

RPC(Rigth Pulic Cotact)

有效联系人(一般指客户本人、父母、配偶、直系亲属)

outbannd/inbound

电话外呼/呼入

二.催收手段介绍

还款日的代扣、短信提醒、客户发送提醒、自动代扣、短线提醒、预测式外呼、预览式外呼、上门催收、法务催收、律师函、委外催收、网络仲裁、IVR 职能语音、上门催收

名词解释:

预测式的外呼(自动外呼):是由坐席人员参与并执行的外呼,坐席人员通过客户端预览分配给自己的外呼任务,然后根据外呼任务,然后根据外呼任务中的电话号码呼叫对方,如果遇到空号、无法接通等情况,坐席人员就要选择下一个号码继续呼叫,直到呼通为止;

预览式的外呼叫(手动外呼):是由外呼系统根据一定算法预测出将要空闲的坐席人数,当前的可呼叫电话等信息,自动对要执行的任务进行外呼,当呼通后才转接到坐席,由座席继续完成后面的工作。

电话催收:催收人员通过电话方式联系欠款人督促其还款的操作称为电话催收

委外催收:通过将债务委托给其他公司或个人进行债务追讨,并按照一定比例支付追讨费用的催收方式

上门催收;去到催收人在居住地址、工作地址等进行债务追讨

法务催收:债权人通过起诉的方式追讨债务的行为称之为法务催收,又可简称为法催、诉讼催收等

三.员工效能指标

合同接通率:当天接通的合同数/当天外呼的合同数

接通率:接通数/外呼次数

RPC比例:联系RPC合同数/接通合同数

PTP比例:承诺还款合同数/联系到RPC的合同数

KPTP:实际还款合同数/承诺还款合同数

工时利用率:接通电话的时长/工作时间(8小时)

跟P比率:跟P的合同量/有效PTP的合同数

四.员工绩效指标

考核周期内的回收合同数量

回收合同量:回收合同量/分配合同量

合同回收率:回收合同量/分配合同量

本金回收率:本金回收金额/分配合同的本金逾期总金额

回收金额:考核周期内的回收总金额

金额回收率:回收金额/分配合同的逾期总金额

本金回收率:本金回收金额/分配合同的本金逾期总金额

五.贷后回收率指标

M1合同回收率:月初1号到月末逾期阶段M1的合同量,分子:月初1号到月末回收阶段为M1的合同量

M2金额回收率:月初1号到月末逾期阶段M1的总逾期金额,分子:月初1号到月末回收阶段为M1的回收金额

M2合同回收率:月初1号到月末逾期阶段M2的合同量,分子:月初1号到月末回收阶段为M2的合同量

Mn合同回收率:月初1号到月末逾期阶段M1的合同量,分子:月初1号到月末回收阶段为M1的合同量

Mn金额回收率:月初1号到月末逾期阶段M1的总逾期金额,分子:月初1号到月末回收阶段为M1的回收金额

六.入催率

CPD1入催率:分母(当月应还合同数) 分子(当月逾期CPD1的合同数)

CPD31入催率:分母(当月累计逾期CPD30天的合同数)分子(当月逾期CPD31的合同数)

CPD61入催率:分母(当月累计逾期CPD60天的合同数)分子(当天挺有趣CPD61的合同数)

出催率:分母(当月逾期合同数)分子(当月CPD0的合同数)

PART2:催收指标与风险联动管控

在以上的指标中,有以下指标影响着风险的联动管控

一.是接通率与失联率

①接通率:在催收拨打电话过程中,接通率一定程度上反映了逾期客户质量,在催收线路无异常的情况下,接通率越低表示客群越差。接通率一般区分关系类型,本人、RPC、TPC等;

②失联率:接通率一般与失联率对应,失联率越高反欺诈风险越大,需要分析是否有集中性等风险

第一个跟风险联动相关的就是接通和失联。在催收打电话过程当中,接通率反映了客户的质量,比如在当前线路没有异常情况下,接通率越低,就表示当前的客群越差。接通率,一般也会区分它不同的关系类型,如本人的接通或者rpc的接通率。通过接通率指标,可以从侧面反映出我们当前的这批客户的质量。与接通率对应的,就是失联率。如果说我发现很多客户都失联了,很大概率就说明这批客户的欺诈概率是很高的,失联率越高的话,它的整个欺诈风险就越大。如果以上两个指标都比较异常,其实就需要反馈到我们贷前团队,要去分析是否是集中性的团伙欺诈的风险,这些从接通的指标都可以有所反馈。

二.是电话沟通内容

①通过设定标准化催收电话结果选项,分析逾期客户不还款原因是还款能力或还款意愿或欺诈或老赖等;

②根据结果及时同步风控团队调整风控策略;

通过整个作业当中的一个电话沟通内容,常常会到系统里面会设定一些标准化的电话结果选项,如:

1.本人是不是否认贷款,

2.本人是不是被冒用贷款,或本人是老赖或欺诈,

3.他的还款意愿强不强

4.接听电话的人不承认是本人

以上等等内容都是设定好的标准化的电话结果选项,然后让催收作业人员在电话沟通后去选择客户属于以上那一类别。

当我们发现某些异常类别占比较高的时候,就应该通知风控团队及时去调整风控策略。

比如目前疫情比较严重的当下,有很多借款人说经济困难无法还债;也有很多人会反映,说他我现在是受疫情影响无法还债。这个情况下,需要视情况分析。因为疫情影响的话,其实问题不大,但是如果说异常占比占比非常高的时候,就可能存在反催收作案,或者有一些特殊的群体,他们就会借这样一个理由来去薅平台羊毛。所以真正的追根溯源的话,会发现有部分人是真实的,但仍少部分人借着这个幌子来去逃避还款。所以需要根据相关指标去做分析,针对性跟分工团队去沟通和调整。

三.是回退率

①催收结果指标,需要从不同维度区分回退率,如多头借贷、新老客、接通未接通等回退率是否趋势一致等;

②同时结合入催率角度分析,逾期MOB账龄等;

③若是新客变差,需要反馈至风控调整策略,如多头越高的客群回收率变坏严重,需要风控控制多头

回退率一般也会是从不同维度,比如多头借贷,还有新老客接通未接通,还会区分不同维度的回退,然后看一下不同维度下的回退率的趋势是否一致,比如说像新客的回退跟老客的回退,以及接通客户的回退跟未接通的回退。

拿多头借贷为例,那些多头高的客群,它最终的回退的趋势是很差的,这样就会反映出风控团队需要调整多头的政策,同时我们也会结合像入催这样的指标综合调整。

再拿入催的资产为例,比如说不同月份的入催的回退。假如以6月份的入催资产,如果他的回退异常变高的时候,就会反映出6月份的某一个风险政策可能出问题了。或者这波客群的某个获客渠道,出现了较大的变动。

综上,一般来说看指标的话,不会简单的去看一个单一的指标。常用的方法会区分客群,然后还会结合入催、回退等多维度,一起综合对比,以上是我们在催收实务上常用的风险联动管控所用的一些特殊指标。

~原创文章

...

end

机器学习|贷款逾期预测(三)模型初训及调优 - 知乎

本文为此项目的第三部分,前两部分链接如下:

3 模型初训及调优

本次主要针对如下几个模型进行训练

逻辑回归LR

决策树

支持向量机SVM

随机森林

GBDT

LightGBM

XGBoost

3.0 准备工作

from

sklearn.preprocessing

import

StandardScaler

from

sklearn.model_selection

import

GridSearchCV

from

sklearn.model_selection

import

train_test_split

# 数据归一化

scaler

=

StandardScaler

()

data_scaled

=

pd

.

DataFrame

(

scaler

.

fit_transform

(

data_extract

),

columns

=

data_extract

.

columns

)

# 切分训练集和测试集(归一化)

X_train_scaled

,

X_test_scaled

,

y_train_scaled

,

y_test_scaled

=

train_test_split

(

data_scaled

,

label

,

test_size

=

0.3

,

random_state

=

2020

)

# 切分训练集和测试集(不归一化)

X_train

,

X_test

,

y_train

,

y_test

=

train_test_split

(

data_extract

,

label

,

test_size

=

0.3

,

random_state

=

2020

)

部分模型训练之前需要将数据归一化,具体可以参考下表:

3.1 逻辑回归

3.1.1 重要参数介绍

C是正则化强度的倒数,必须是一个大于0的浮点数,不填写默认1.0,即默认正则项与损失函数的比值是1:1。C越小,损失函数会越小,模型对损失函数的惩罚越重,正则化的效力越强,参数

\theta

会逐渐被压缩得越来越小。

penalty:str,default: 'l2'

可以输入"l1"或"l2"来指定使用哪一种正则化方式,不填写默认"l2"。 注意,若选择"l1"正则化,参数solver仅能够使用求解方式”liblinear"和"saga“,若使用“l2”正则化,参数solver中所有的求解方式都可以使用。

class_weight : dict or 'balanced', default: None

指定每个类的权重,未指定时所有类都默认有同一权重。“平衡”模式使用y的值来自动调整与输入数据中的类频率成反比的权重,即n_samples / (n_classes * np.bincount(y)).

solver : str,{'newton-cg','lbfgs','liblinear','sag','saga'},default: 'liblinear'

用于求解模型最优化参数时的算法,即最优化问题的算法。对于小数据集,'liblinear'是一个好选择,而'sag' 和 'saga'对大数据集训练更快。对于多分类问题,只有'newton-cg','sag', 'saga' 和 'lbfgs' 能处理多元损失,'liblinear' 仅限于一对多 'one-versus-rest' 和普通二分类。

max_iter : int,default: 100

最大迭代次数。

3.1.2 参数调优

from

sklearn.linear_model

import

LogisticRegression

param_grid

=

{

'penalty'

:[

'l1'

,

'l2'

],

'C'

:

np

.

arange

(

0.005

,

0.1

,

0.005

),

'solver'

:

[

'liblinear'

,

'lbfgs'

,

'newton-cg'

],

'class_weight'

:

[

'balanced'

,

None

]

}

log_grid

=

GridSearchCV

(

LogisticRegression

(

random_state

=

2020

,

max_iter

=

1000

),

param_grid

,

cv

=

5

)

log_grid

.

fit

(

X_train_scaled

,

y_train_scaled

)

log_grid

.

best_estimator_

,

log_grid

.

best_score_

# 取出lr模型

log

=

log_grid

.

best_estimator_

model_metrics

(

log

,

X_train_scaled

,

X_test_scaled

,

y_train_scaled

,

y_test_scaled

)

得出结果如下:

3.2 决策树

3.2.1 重要参数介绍

criterion:str or None,default='gini'

用来衡量不纯度的指标。输入'gini'使用基尼指数,输入'entropy'使用信息增益。

splitter:str or None,default='best'

确定每个节点的分枝策略,'best'使用最佳分枝。

max_depth : int or None,optional (default=None)

树的最大深度,如果设置为None则直到叶节点只剩一个或者少于min_samples_split时停止。

min_samples_leaf:int,float or None,default=1

一个叶结点存在所需要的最少样本量,一个节点在分枝后的每个子节点中必须包含至少min_samples_leaf个训练样本,否则分枝不会发生。

max_features : int,float,string or None,optional (default=None)

在寻找最佳分割时考虑的特征数,设置为’auto’时max_features=sqrt(n_features)

class_weight : dict,list of dicts,“balanced” or None,default=None

指定每个类的权重,未指定时所有类都默认有同一权重。“平衡” 模式使用 y 的值来自动调整与输入数据中的类频率成反比的权重,即 n_samples / (n_classes * np.bincount(y)

3.2.2 参数调优

from

sklearn.tree

import

DecisionTreeClassifier

gini_thresholds

=

np

.

linspace

(

0

,

0.5

,

20

)

parameters

=

{

'splitter'

:(

'best'

,

'random'

)

,

'criterion'

:(

"gini"

,

"entropy"

)

,

"max_depth"

:[

*

range

(

1

,

10

)]

,

'min_samples_leaf'

:[

*

range

(

1

,

50

,

5

)]

,

'min_impurity_decrease'

:[

*

np

.

linspace

(

0

,

0.5

,

20

)]

}

GS

=

GridSearchCV

(

DecisionTreeClassifier

(

random_state

=

2020

),

parameters

,

cv

=

10

)

GS

.

fit

(

X_train

,

y_train

)

# 绘图

model_metrics

(

GS

.

best_estimator_

,

X_train

,

X_test

,

y_train

,

y_test

)

3.3 支持向量机SVM

3.3.1 重要参数介绍

表示错误项的惩罚系数。C越大,即对分错样本的惩罚程度越大,因此在训练样本中准确率越高,但是泛化能力降低;相反,减小C的话,容许训练样本中有一些误分类错误样本,泛化能力强。对于训练样本带有噪声的情况,一般采用后者,把训练样本集中错误分类的样本作为噪声。

kernel: str,default = 'rbf'

该参数用于选择模型所使用的核函数,算法中常用的核函数有:

linear:线性核函数

poly:多项式核函数

rbf:径像核函数/高斯核

sigmod:sigmod核函数

gamma : float,default=auto

该参数为核函数系数,只对‘rbf’,‘poly’,‘sigmod’有效。如果gamma设置为auto,代表其值为样本特征数的倒数,即1/n_features,也有其他值可设定。

class_weight: dict or 'balanced',default=None

该参数表示给每个类别分别设置不同的惩罚参数C,如果没有给,则会给所有类别都给C=1,即前面参数指出的参数C。如果给定参数‘balance’,则使用y的值自动调整与输入数据中的类频率成反比的权重。

3.3.2 参数调优

发现用SVM的话,存在一定的过拟合问题,使得模型在训练集上的表现优于在测试集的表现。

from

sklearn.svm

import

SVC

param_grid

=

{

'C'

:

np

.

arange

(

0.05

,

3

,

0.05

),

'gamma'

:

[

'auto'

,

0.01

,

0.5

],

'kernel'

:[

'liner'

,

'rbf'

,

'poly'

,

'sigmod'

]

}

svc_grid

=

GridSearchCV

(

SVC

(

random_state

=

2020

,

probability

=

True

),

param_grid

,

cv

=

5

)

svc_grid

.

fit

(

X_train_scaled

,

y_train_scaled

)

svc_grid

.

best_estimator_

,

svc_grid

.

best_score_

model_metrics

(

svc_grid

.

best_estimator_

,

X_train_scaled

,

X_test_scaled

,

y_train_scaled

,

y_test_scaled

)

仔细查看,虽然准确率较决策树和逻辑回归有所提升,但是召回率较低。

当给SVM模型添加class_weight='balanced'后,发现模型准确率降低,但是召回率明显升高,如下图所示:

需要进一步调节模型参数。