评分卡
本文为根据风控课程总结
个人信贷产品的信用评分
商业银行三大风险流动性风险、市场风险(利率、信用)和操作风险,其他(欺诈风险)
信用风险:在合约到期日不完全履约
信用风险重要参数:PD(违约概率)、LGD(违约条件下的损失率)、EAD(违约风险下的敞口暴露)、RWA(风险权重资产)、EL(期望损失)
银行风控步骤
准入规则---》Pre A模型----》反欺诈----》新的规则----》A卡----》B卡
一般这里面不用选用相同的特征。这是因为客户由于一些特征上表现差才会被拒绝,而随着时间的偏移,这样会出现偏差,因为迭代到下一个模型的时候,用之前的特征规则虽然表现好,但筛选掉的用户将不在我们的建模样本里,特征的样本分布已经改变了。
A卡的y一般可以用客户历史逾期天数最大的天数来定义;B卡的y一般则可以用多期借款中逾期最大的一次。
什么是评分卡模型
以分数形式来衡量风险几率的一种手段。
是对未来一段时间内违约/逾期/失联概率的预测。(每个评分卡对应的都有对应的人群)
通常分数越高越安全。
申请评分卡(资信状况)、行为评分卡(消费账户历史上表现,通常进行行为评分卡的产品期限至少会是半年以上还款的才能看到历史表现,比如房贷、车贷、信用卡有循环贷款的模式比较适用)、催收评分卡(违约概率评分卡(轻度逾期到违约)、损失回收评分、催收响应类评分卡)
评分卡常用模型
逻辑回归:简单、稳定、可解释、易于监测和部署 缺点准确率不高
决策树:对数据质量要求低(数值型非数值、缺失容忍、共现容忍)、易解释 缺点准确率不高
组合模型:准确率高、不易过拟合 缺点不易解释、计算量大
坏样本定义
M3 &M3+ 、债务重组、个人破产、银行主动关户或注销
时间窗口
观察期与表现期(行为评分卡)
表现期:搜集是否触发坏样本定义的时间窗口,与前面M1\M0什么的没关系,通常6个月~1年,但也不能定的过长,因为你的贷款产品的还款周期是固定的,如果表现期定的过长,那观察期的数据就会变少。过短模型会不稳定。
观察期:搜集特征的时间窗口,通常3年以内; 带有时间切片的变量(如果你的特征有多是长期特征,而你的新客户又没有使用很长时间的信贷产品,那不太适合放在这个评分卡里面)
行为评分卡
y:贷款产品用户在放贷后、产品期限结束之前的某段时间(表现期)内违约或逾期风险
适用产品:分期付款的产品房贷、车贷、装修贷;循环授信产品信用卡或纯信用类现金贷
特征构造
业务上所需要的变量是什么样的呢?
1.变量必须对模型有贡献,也就是说对客群加以区分
2.缺失值的填充,可以考虑使用同样坏账率区间的样本去填充
3.逻辑回归要求变量之间线性无关(不是正交基不能学习的很完整)的
4.评分卡模型通常要求变量呈现单调的趋势,也就是BIVar, 首先是业务角度这样更过关,比如贷款次数越多的bad_rate应该越高 ,还有就是对于最后评分卡来说,值越大分加的分越多;其次是逻辑回归模型本身更可能处理这种单调的变量。
5.客群在每个变量的分布式稳定的,分布迁移无可避免,但不能波动太大(特征的稳定性,一个是计算PSI 另一个是可以通过做跨时间交叉验证即1月做测试集,其他的做训练集,求特征重要度,2月的做测试集,其他的做训练集,求特征重要度,。。依次,把各组求出的特征求交,每次进入模型的特征即为稳定的特征,见金融风控中的06 LightGBM评分卡.ipynb)
#BIVar图
# 等频切分 df_train.loc[:,'fare_qcut'] = pd.qcut(df_train['Fare'], 10) df_train.head() df_train = df_train.sort_values('Fare') alist = list(set(df_train['fare_qcut'])) badrate = {} for x in alist: a = df_train[df_train.fare_qcut == x] bad = a[a.label == 1]['label'].count() good = a[a.label == 0]['label'].count() badrate[x] = bad/(bad+good) f = zip(badrate.keys(),badrate.values()) f = sorted(f,key = lambda x : x[1],reverse = True ) badrate = pd.DataFrame(f) badrate.columns = pd.Series(['cut','badrate']) badrate = badrate.sort_values('cut') print(badrate) badrate.plot('cut','badrate')
特征选择
特征选择通常考虑两个方面,一是特征是否发散,即方差(一般针对分类变量,因为数值变量存在量纲问题,方差大小与量纲相关);二是特征与目标的相关性
现在很多公司不再精调,一个个看BIVar图了,二是直接xgboost看重要度
基于重要度的特征筛选一般就是,1.IV值 2.卡方检验 3.模型筛选 选一种就好
有些风控会考虑变量的稳定性,会用PSI来筛选
#生成可以传入PSI的数据集 def make_psi_data(dff_train): dftot = pd.DataFrame() for col in dff_train.columns: zero= sum(dff_train[col] == 0) one= sum(dff_train[col] == 1) ftdf = pd.DataFrame(np.array([zero,one])) ftdf.columns = [col] if len(dftot) == 0: dftot = ftdf.copy() else: dftot[col] = ftdf[col].copy() return dftot psi_data_train = make_psi_data(dff_train) psi_data_val = make_psi_data(dff_val) #定义根据psi_data计算psi的函数 def var_PSI(dev_data, val_data): dev_cnt, val_cnt = sum(dev_data), sum(val_data) if dev_cnt * val_cnt == 0: return 0 PSI = 0 for i in range(len(dev_data)): dev_ratio = dev_data[i] / dev_cnt val_ratio = val_data[i] / val_cnt + 1e-10 psi = (dev_ratio - val_ratio) * math.log(dev_ratio/val_ratio) PSI += psi return PSI psi_dct = {} for col in dff_train.columns: psi_dct[col] = var_PSI(psi_data_train[col],psi_data_val[col])
常用特征
时间切片特征,例如观察期之前180天内,平均每月的逾期次数
时间序列衍生特征,(基础特征,月份)假设基础特征为“加油金额”,分别计算出最近1月、2月、3月。。。6月的“加油金额”然后由此再衍生出,最近几个月加油金额>0的次数、等于0的次数、最近1个月/以往平均金额等等变量
还款率类型特征(本月还款率,过去半年内最大的还款率,过去半年内平均月还款率)、额度使用率特征(过去6个月内平均额度使用率,过去6个月内额度使用率增高的次数)、逾期类特征(过去6个月的最大逾期状态、过去6个月M1\M2\M3的次数)、消费类型特征(“国外使用”类型特征,“提现“”类型特征)
特征分箱
分箱:将连续变量离散化,除此之外将多状态的离散变量合并为少状态也属于。
分箱的重要性:1.连续变量离散化,robust更强不易受噪声影响;2.分箱后one-hot变成N个变量,引入了非线性,增强了逻辑回归的表达 3.离散化后模型也会更稳定 4.离散化后还可以做特征交叉 5.不离散的话评分卡没法做成加法减法的形式。
分箱的优势:可以将缺失值作为一箱,将所有变量转换到同一尺度
分箱的限制:计算量大、分箱后需要编码;
要求:分箱后要保证变量的单调性,不单增的变成单调的(更粗的分箱)
分箱的方法:
best-ks:
卡方分箱:相邻的属性对坏事件的相关性是不是一致,一致就合并。依赖于阈值的选定,也可以考虑最小区间数或最大区间数。
自由度是类别数-1,在置信度给定的情况下确定卡方阈值。
等距分箱、等频分箱
分箱的注意点: 连续变量如果有特殊值需要单独分箱。例如在还款率变量中,有时需将“上月末欠款额为0”的情形设置为特殊值-1,此时需要单独分箱。
WOE编码
分箱完之后的组别没有任何意义,所以需要编码。评分卡里面常用的编码是WOE编码,要计算WOE每个组别里面必须同时有好坏样本。
woe处理后,逻辑回归变量前面的系数已经不是越大越重要了,因为WOE本身已经是重要度了,此时逻辑回归变量前的系数就是拟合值。
以前风控公司一定会做WOE,现在有些不做,有些只有文本型的做,数值型的不做,因为其他模型使用WOE只能带来千分位的模型提升。
WOE的符号与好样本比例相关,要求回归模型的系数为负(坏样本比例值要小)
IV值
衡量特征包含预测变量浓度的一种指标。该变量的IV值是每一箱的IV值相加,一个变量只有一个IV。而IV是从加权后的WOE(权重是衡量差异的重要性,绝对值的重要性),WOE是每一箱都有的。一般分箱数越多IV值会越高,所以在计算IV值前要做较好的分箱。
用户衡量变量的区分度。
IV一定是正值、一个变量只有一个IV。
woe后如果变量的符号是正的,和我们的业务逻辑是相反的,我们认为该变量有问题。当我们特征工程完了以后,对于大部分变量我们不能直接丢到模型里面去的,需要做变量筛选,包括单变量分析和多变量分析。
单变量分析
分箱后的WOE值。
1. 如果分箱后,某一个特征的某一个值占比达90%以上,我们不建议把这个特征放到模型里面去。在分箱之前如果某变量的方差很小也可以提前进行删除。
2. 保证bad rate的单调性(U型也可以,再奇怪的不可以,要么拿掉要么重新处理分箱),但不能保证WOE的单调性,一般WOE不单调可能是某一箱占比过小
3. IV值要么0.1要么0.2
双变量分析
1. 消除两两变量的相关性。可以预估变量重要性,继而选择重要性更高的变量,例如借助与随机森林或GBDT对特征重要度的排序
2. 变量的多重共线性,β的估计无偏,但是会影响显著性。计算每个特征相对于其他特征的VIF,如果发现某个特征的VIF比较高,需要逐项排查是哪一个或哪几个,然后再根据IV决定拿掉哪个。
行为评分卡模型构建
逻辑回归不适合放很多变量,一般现实中使用IV+随机森林进行变量挑选。挑选完变量后,运行逻辑回归模型要求1. 系数的符号为负(woe=ln(G/B),如果没有做WOE不需要统一符号为负) 2.系数显著
逻辑回归一般选择L2正则效果更好。里面的class weight参数可以解决类别不平衡问题。
Lasso在保证一定精度的情况下,考虑模型的复杂度。
从模型到分数,参数前面负号和y前面的负号抵消了,
50这个数值就是PDO,随着模型的更新需要动态调整,保障各区间(A B C D)的分数刻度不变,保障每个区间的人数比例不会波动太大
def score(person_info,finance_info,credit_info,act_info): xbeta = person_info * ( 3.49460978) + finance_info * ( 11.40051582 ) + credit_info * (2.45541981) + act_info * ( -1.68676079) --0.34484897 score = 650-34* (xbeta)/math.log(2) return score
如果是xgboost模型转换成分数,可以直接把概率进行替换
def score(xbeta): score = 1000-500*(math.log2(1-xbeta)/xbeta) #好人的概率/坏人的概率 return score evl['xbeta'] = model.predict_proba(evl_x)[:,1]
模型过拟合的处理方法
1. 特征筛选减少特征 2.正则 3.分箱的箱子划分更粗一点(变量变得更稳定)4.增加样本(一般做不到)
模型验证与监控
1.监控通常会看通过率(捕获率),看上线后各组的捕获率是不是还是前面的组就可以捕获大部分坏人。
2.分数的分布,客群没有发生太大变化,但分数越来越低了,这种时候会对模型改动。低分原因分析。
3. 还会看主要特征的PSI和模型的PSI
4. 模型的KS值, KS和AUC实际是一样的,只是坐标不一样
样本不均衡
1.半监督算法
拒绝推断,从模型预测出的每个分组里面取出一定比例的黑样本,作为扩充
用半监督的算法,把样本分成两类,分别用不同的特征训练,然后再分别交叉进行预测,将预测出的高概率样本标记为黑样本
2.代价敏感学习
利用不同分类的样本被误分类而产生不同的代价,即给予不同的样本不同的权重,模型的fit里面都有参数(sample_weight= )
3.采样算法
朴素随机采样
Smote 对于少类样本a,随机选择一个最近邻的样本b,然后从a与b的连线上随机选取一个c作为新的少数类样本。这个方法比较容易过拟合
Borderline-Smote-1 只对靠近边界的样本去造新的负样本,这样可以让我们学习到更清晰的边界。推荐使用。
from imblearn.oversample import SMOTE
SMOTE(kind = 'borderline1')
过拟合问题
1.找更多的数据集来学习,缓解过拟合问题
2.特征选择,降低特征维度
3.用差异化的模型去做模型融合
风控实践中问题
可参考 https://github.com/xsj0609/data_science/tree/master/ScoreCard
1.模型效果不好
数据就有问题
2.训练集效果好,跨时间测试效果不好
样本分布不一样导致
解决方法:去掉表现很不一样的特征。
没办法的时候用,存在泄漏, 在跨时间测试集上训练一个模型,然后去之前的8个月上做预测,悬着跨时间测试集里面的变量去训练集里面训练,再在跨时间上去做
3.跨时间测试效果也好,上线后效果不好
原因1:线上线下做变量的逻辑不一致
原因2:可能包括了未来信息的变量做进来了
4.上线之后效果好,几周后分数分布开始下滑
即几周后,根据拒绝率划分的A\B\C\D类客户,出现A类客户下滑到了B
模型的问题,效果不好
有一两个变量在跨时间上表现不好
5.一两个月内比较稳定,突然分数分布骤降
关注外部环境变化,是否政策变化,某个行业是不是暴雷了,运营拉了新客
6.没有明显问题,但模型每个月逐步失效
正常的