风控case demo总结

 参考:金融风控项目(数据分析最后阶段精华总结很久!)_风控 漏斗-CSDN博客

1. 信贷常识

        信贷业务(贷款业务)通过放款收回本金和利息,扣除成本后获得利润。贷款平台预测有信贷需求用户的还款情况,然后将本金借贷给还款概率大的用户;风控则是对用户的信用风险进行管理与规避,对于预测信用较差的人,不向其放款,即便放款,也会是较小的贷款额度和较高的利率。信贷领域有两类风险:

 信用风险(信用评分系统):借款人的的还款能力和还款意愿在贷款后出现问题的风险;

 欺诈风险(反欺诈系统):借款人压根没想还钱,以诈骗为目的。

1.1 常见风险介绍

    1. 冒名顶替,黑产骗贷

    2. 多头借贷,借新还旧

        客户:工行信用卡,招商信用卡... n张信用卡,网贷平台1,网贷平台2,网贷平台n;

        特点:

1. 第三方数据:多头申请记录;

2. APP安装:大量借款类APP;

3. 短信:大量申请短信,提醒还款,催收短信。

    3. POS机套现,以少换多

        购买有支付牌照机构的POS机进行套现,手续费0.6%;

   4. 针对风控模型,制作数据

  • 使用花呗在天猫购物,对花呗账单做分期;

  • 买入存金宝,一个礼拜后追加存金宝资金;

  • 购买***元基金;

  • 保持余额宝XXX元不动,余额宝累计收益做到 XX元;

  • 购买XXXX保险。

1.2 风控相关术语

名称含义备注
DPD逾期天数(Day past due)

DPD0为到期当日,

DPD1为逾期一日

FPD首次逾期天数(First time past due)
F/S/T/QPD 首次/二次/三次/四次逾期天数
M1逾期 [1, 30)天Months
M1+逾期[30, inf]天
bad rate 坏账率当月不良资产数/总资产数
vintage    账龄分析
default坏账
flow rate流动率一般指M1向M2,M2向M3转移的比例


    

2. 信贷业务整体逻辑

2.1 信贷业务如何运行

    1. 市场部门 → 获客(新客转化/存量激活)

            地推 | 电销 | 营销短信 | 平台广告(抖音, 微信, 微博……)

           不同获客方式 ,不同人群是否在后期表现都一致。

            存量用户召回 → 利率优惠,免息券

    2. 风控部门 → 筛选用户(是不是目标客群)

            要不要放款 | 给多少额度 | 给多少利率 | 给多少期

            找到额度,利率的最佳平衡点。

    3. 催收部门 → 资金回收(催收)

            不同的客户使用不同的话术,不同的催收策略是否有不同的催收效果。

2.2 信贷业务行为路径与转化漏斗

    1. 基础概念

首贷:第一次借款成功;

复贷:借完一次之后,再次借款;

新客:没放过款的客户(可能是第一次来,也可能是之前的申请被拒接了);

老客:放过款的客户;

状态表:记录某一时刻的状态(记录当前时刻或当天的状态,覆盖历史的状态);

log日志表:记录从开始到现在所有的数据,有一次操作或者更新就记录一条。

    2. 信贷业务转化漏斗

        注册 → 申请 → 放款 → 还款

    3. 业务报表介绍

 1. 注册表: 不包含注册未完成的用户(有手机号,但是没有user_id);

 2. 用户信息表;

 3. 借款表: 每次申请都会有一条记录;

 4. 放款表: 亦称还款计划表,是一个状态表,只会记录还款信息最新的状态;

 5. 还款表: 记录每一笔还款情况,同一个订单可能会有多次还款;

 6. Vintage报表:葡萄酒的酿造年份。

       在比较放贷质量时,要按账龄MOB(month of book)的长短同步对比,从而了解同一产品不同时期放款的资产质量情况。vintage将不同时期的数据拉平到同一时期比较,可以很直观地比较和反思不同时期公司的营销策略的效果。

2.3 风控报表指标

    1.  市场部门

        各个阶段转化率、各个渠道花费及效率、每个页面的留存率;

    2. 风控部门

        通过率、放款、件均、逾期率(整 | 单笔逾期, 金额逾期)、规则命中率、客群分布、vintage表等;

    3. 催收部门

        催回率、不同催收阶段、不同催收员的催回、接通率表、 接通时长表。

3. 风控建模概述

3.1 互金风控体系介绍

1. 四要素认证:银行卡持有人的姓名、身份证号、银行卡号、手机号;

2. 用户数据:

1. 用户基本信息: 联系人,通讯录,学历...;

2. 用户行为信息: 操作APP时的行为,注册,点击位置...;

3. 用户授权信息: 运营商,学信网,设备IMEI....;

4. 外部接入信息: 收费的征信数据、各种信息校验、外部黑名单之类、P2P信贷及其它金融机构如芝麻信用分...

3. 策略体系:

1. 反欺诈规则;

2. 准入规则:年龄,地域,通讯录,行为规则;

3. 运营商规则:通话规则;

4. 风险名单:黑名单,失信名单,法院名单;

5. 网贷规则:多头,白户...

4. 机器学习模型:欺诈检测模型、准入模型、授信模型、风险定价、额度管理、流失预警、失联修复。

贷前准入贷中管理贷后催收
信用申请评分卡行为评分卡催收评分卡
反欺诈申请反欺诈交易反欺诈
运营用户响应模型用户流失模型、用户分群、用户画像失联修复
其他套现识别、洗钱识别  

3.2 风控建模流程

3.2.1 评分卡简介

        风控模型其中包含了A/B/C卡。模型可以采用相同算法,一般以逾期天数来区分正负样本,即目标值Y的取值(0或1)。

评分卡类型适用客群备注
贷前申请评分卡(Application score card)新客
贷中行为评分卡(Behavior score card)未逾期老客
贷后催收评分卡(Collection score card)逾期老客因用途不同Y的取值可能有区别,比如公司内催,外催

   3.2.2 模型完整流程

阶段流程明细备注
项目准备明确需求目标人群、给予产品
模型设计业务抽象成分类/回归问题

只有欺诈检测不是二分类问题,因样本数量不足,可能是无监督学习。

规则模型、逻辑回归、集成学习、融合模型

定义标签通常选一个截断点(阈值),来划定负样本;训练去掉“灰样本”,测试时加入,用于确保模型对该部分样本也有区分能力。
样本设计(样本选取)代表性、充分性、时效性、排除性对行为评分卡用户、无还款表现或欺诈用户均不应放入当前样本集
特征工程数据处理明确数据的质量,覆盖度,稳定性
特征构建每个属性都可以从R(Recency)、 F(Frequency)、M(Monetary)三个维度来构建特征
特征评估

覆盖度高、稳定性好、PSI区分度好、好坏用户的特征值IV差别大

PSI(Population Stability Index)区分度好、单特征AUC、单特征KS
模型构建模型训练
模型评估跨时间稳定性、区分度(抓坏人能力在不同分段的表现)在后续较长时间可以持续使用 PSI 区分度好,好坏用户的信用分差别大 AUC, KS, GINI
模型调优
上线运营模型交付特征|模型报告
模型部署使用PMML文件或Flask API进行部署确保开发环境和生产环境一致性,对一批客户进行离线打分和线上打分,确保离线结果和线上结果一致
模型监控特征|模型稳定性

        观察期:用户申请信贷产品前的时间段;

        表现期:定义好坏标签的时间窗口,如果在该时间窗口内触发坏定义就是坏样本,反之就是好样本。

3.3 业务规则挖掘

        使用一系列判断逻辑对客户群体进行区分,不同群体逾期风险有显著差别,如果一条规则将用户划分到高风险组,则直接拒绝,如果划分到低风险组则进入到下一规则。如:多头借贷数量是否超过一定数量。

       可以通过AI模型辅助建立规则引擎,决策树很适合规则挖掘的场景。

4. 特征工程

4.1 单特征分析

特征衡量指标:

1. 覆盖度:缺失率、零值率;

        业务越来越成熟,覆盖度可能会越来愈好,可以通过运营策略提升覆盖度;

2. 区分度:是评估一个特征对好坏用户的区分性能的指标。

(1)可以把单特征当做模型,使用AUC、KS来评估特征区分度;

(2)在信贷领域,常用 IV(刻画了一个特征对好坏用户分布的区分程度) 来评估单特征的区分度;

IV<0.02 区分度小, 建模时不用 (xgboost,lightGMB 对IV值要求不高);

IV [0.02,0.5] 区分度大, 可以放到模型里;

IV > 0.1 考虑是否有未来信息;

IV > 0.5 单独取出作为一条规则使用,不参与模型训练。

模型中尽可能使用区分度相对较弱的特征,将多个弱特征组合,得到评分卡模型;

连续变量的IV值计算,先离散化再求IV,跟分箱结果关联很大(一般分3-5箱)。

3. 相关性:

(1)特征与标签之间的相关性:

皮尔逊相关系数 pearson,斯皮尔曼相关系数 spearman,肯德尔相关系数 kendall

连续型数值变量无序分类变量有序分类变量
连续型数值变量pearson(具有正态性)、spearman、kendallkendallkendall
无序分类变量kendall--
有序分类变量kendall-spearman

  适用性:kendall > spearman > pearson

(2)特征与特征之间的相关性:

         可以使用toad库来过滤大量的特征,高缺失率、低iv和高度相关的特征一次性过滤掉。缺失率大于0.5,IV值小于0.05,相关性大于0.7来进行特征筛选。

4. 稳定性:特征稳定性主要通过计算不同时间段内同一类用户特征的分布差异来评估,常用PSI。 

1. 当两个时间段的特征分布差异大,则PSI大,反之则PSI小;

2. IV是评估好坏用户分布差异的度量,PSI是评估两个时间段特征分布差异的度量;

    两者都是评估分布差异的度量,并且公式其实一模一样,只是符号换了而已。

4.2 多特征筛选

        过多的特征会导致模型训练变慢,学习所需样本增多,计算特征和存储特征成本变高。常用的特征筛选方法:

    1. Boruta: 是一种特征选择方法,使用特征的重要性来选取特征。

pip install Boruta
conda install -c conda-forge boruta_py

使用Boruta,选择features

from boruta import BorutaPy
y = pd.read_csv('test_y.csv', header=None, index_col=0).values
y = y.ravel()
rf = RandomForestClassifier(n_jobs=-1, class_weight='balanced', max_depth=5)
feat_selector = BorutaPy(rf, n_estimators='auto', verbose=2, random_state=1)
feat_selector.fit(X, y)
print(feat_selector.support_)  # 返回特征是否有用,false可以去掉
print(feat_selector.ranking_)
X_filtered = feat_selector.transform(X)
for ft, seleted in zip(pd_x.columns.to_list(), feat_selector.support_):
    dic_ft_select[ft] = seleted
pd_ft_select = pd.DataFrame({'feature':pd_x.columns.to_list(), "selected": feat_selector.support_})

  2. 方差膨胀系数VIF(Variance inflation factor):

          如果一个特征是其他一组特征的线性组合,则不会在模型中提供额外的信息,可以去掉。可以使用VIF评估共特征线性程度。

$\rm{VIF=\frac{1}{1-R^2}}$

    R^2是线性回归中的决定系数,反映了回归方程解释因变量变化的百分比。它可以由因变量和自变量之间的复相关系数的平方得到,也可以由回归方程的残差平方和和总平方和的比值得到。为了得到每一个变量的VIF,需要以每一个变量为因变量对其余所有变量进行线性回归分析,对每一个变量得到各自的R2,再代入上面的式子,就可以得到每一个变量的VIF了。

        VIF越大说明拟合越好,该特征和其他特征组合共线性越强,就越没有信息量,可以剔除。

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

     使用排除法的方式训练模型,把模型性能下降最少的那个特征去掉,反复上述训练直到达到指定的特征个数。

4. 基于L1的特征选择 (L1-based feature selection)

    使用L1范数作为惩罚项的线性模型会得到稀疏解:大部分特征对应的系数为0。可以选择不为0的系数。常用于此目的的稀疏预测模型有 Lasso回归、LogisticRegression、LinearSVC分类。

4.3 内部特征的监控

1. 前端监控(授信之前):特征稳定性

    大多数情况下,随着业务越来越稳定,缺失率应该呈现逐渐降低的趋势;特征维度的PSI如果>0.1可以观察一段时间。

2. 后端监控(放款之后): 特征区分度

AUC/KS 波动在10%以内;

KS 如果是线上A卡 0.2是合格的水平;

IV值的波动稍大可以容忍,和分箱相关,每周数据分布情况可能不同,对IV影响大一些。

3. 分箱风险区分:要重视每个特征的风险趋势单调性

每一箱 的bad_rate有波动,容忍度相对高一些;

高度重视不同箱之间风险趋势发生变化

如果风险趋势单调性发生变化,要考虑特征是不是要进行迭代。

4.4 外部特征评估

    1. 数据评估标准:覆盖度、区分度、稳定性;

    2. 避免未来信息:使用外部数据的时候,可能出现训练模型的时候效果好,上线之后效果差;取最近一个时间周期的数据,之前3~4个月或者更长时间的数据做验证,看效果是不是越来越差。

   3. 避免内部数据泄露

如果需要把数据交给外部公司让对方匹配,一定要将内部信息做Hash处理再给对方匹配;

匹配上的是共有的数据,匹配不上的外部无法得知其身份。

5. 金融风控场景下样本不均衡解决方案

        1. 下探(最直接的解决方法):在被拒绝的客户中放一部分人进来,即通过牺牲一部分收益,积累负样本,供后续模型学习。

   下探的代价很明显:风险越高,成本越高。它会造成信用质量的恶化,不是每个平台都愿意承担这部分坏账,并且往往很难对每次下探的量给出一个较合适的参考值。

         2. 半监督学习

        3. 代价敏感:代价敏感加权在传统风控领域又叫作展开法,依赖于已知表现样本的权重变化,通常对少数类样本进行加权处理,使得模型进行均衡训练。假设拒绝样本的表现可以通过接收样本直接推断得到。

        4. 采样算法:欠采样、过采样。

6. 一些技巧

(1)应用异常检测算法进行数据清洗;

(2)PreA模型预筛选样本。

        贷款用户首次申请贷款时,平台通常要查询外部收费数据,如征信数据等,从而更好地评估用户信用情况。PreA模型指在申请评分卡之前,设置一张根据免费数据进行粗筛选的评分卡,用一些免费数据对用户进行初筛,避免资金浪费(被拒绝的用户调用收费数据,这部分用户数据的钱相当于白花了)。

1. preA模型可以拒绝很少量的客群,其中大部分是负样本;

2. 使用异常分数作为PreA模型的评分,使用0.7分作为正负样本的分割阈值。

(3)模型表现越来越好之后,人工审核的需求会逐步降低,但不会去掉;一般算法模型上线后,在高分段和低分段模型表现较好,中间的用户还是可能需要人工参与审核。

7. 模型训练与评估

7.1 模型训练

    目前风控业务还是使用机器学习模型,少数公司在尝试深度学习。

模型的可解释性 > 稳定性(PSI) > 区分度(AUC、KS)

      业务指标:通过率、逾期率

1. 逾期率控制在比较合理的范围的前提下,要提高通过率;

2. A卡,要保证一定过得通过率,对逾期率可以有些容忍;

3. B卡,想办法把逾期率降下来,好用户提高额度。

7.2 评估报告生成

      计算出报告中所需要的字段:KS值、负样本个数、正样本个数、负样本累计个数、正样本累计个数、捕获率、负样本占比。

      1. 准备数据

bins = 20
df = pd.DataFrame()
df['real_bad'] = val_y  # 真实结果
df['bad_rate_predict'] = lr_model.predict_proba(val_x)[:,1]  # 预测结果(坏人概率)
df = temp_.sort_values('bad_rate_predict', ascending = False)  # 按照预测坏人概率降序排列
df['num'] = [i for i in range(df.shape[0])]  # 添加序号列,用于分组
df['num'] = pd.cut(df.num, bins = bins, labels = [i for i in range(bins)])  # 分成20组,为每组添加组号

         2. 创建报告

report_df = pd.DataFrame()
# 计算每一组坏人数量
report_df['BAD'] = df.groupby('num').real_bad.sum().astype(int)
# 累计求和坏人数量
report_df['BAD_CNT'] = report_df['BAD'].cumsum()
bad_total = report_df.BAD_CNT.max()

# 计算每一组好人数量
report_df['GOOD'] = df.groupby('num').real_bad.count().astype(int) - report['BAD']
# 累计求和好人数量
report_df['GOOD_CNT'] = report_df['GOOD'].cumsum()
good_total = report_df.GOOD_CNT.max()

# 计算当前组坏人概率
report_df['BADRATE'] = report_df.apply(lambda x: round(x.BAD/(x.BAD+x.GOOD),3), axis=1)
# 计算到当前组坏人比例(占所有坏人比例)
report_df['BAD_PCTG'] = round(report_df.BAD_CNT/bad_total, 3)

         3. 计算 KS

def cal_ks(x):
    # 当前箱累计坏人数量/总坏人数量 - 当前箱累计好人数量/好人数量
    ks = (x.BAD_CNT/bad_total) - (x.GOOD_CNT/good_total)
    return round(math.fabs(ks), 3)

report['KS'] = report_df.apply(cal_ks, axis=1)
print(report)

  

      4. 输出报告

可以看出:

1. 模型的KS最大值出现在第6箱(编号5),如将箱分的更细,KS值会继续增大,上限为前面通过公式计算出的KS值;

2. 前4箱的样本占总人数的20%,捕捉负样本占所有负样本的56.4%,如拒绝分数最低的20%的人,可以捕捉到56.4%的负样本。

       5. 绘制负样本占比和KS值图

from pyecharts.charts import *
from pyecharts import options as opts
from pylab import *
mpl.rcParams['font.sans-serif'] = ['SimHei']
np.set_printoptions(suppress=True)
pd.set_option('display.unicode.ambiguous_as_wide', True)
pd.set_option('display.unicode.east_asian_width', True)
line = Line()
line = line.add_xaxis(report.index.values.tolist())
line = line.add_yaxis("分组坏人占比", list(report_df.BADRATE), yaxis_index=0, color="red")
line = line.set_global_opts(title_opts=opts.TitleOpts(title="评分卡模型表现"))
line = line.extend_axis(
    yaxis=opts.AxisOpts(name="KS值", type_="value", min_=0, max_=0.5, position="right",
           axisline_opts=opts.AxisLineOpts(linestyle_opts=opts.LineStyleOpts(color="red")),
    axislabel_opts=opts.LabelOpts(formatter="{value}"))
)
line = line.add_yaxis("KS", list(report['KS']), yaxis_index=1, color="blue",
    label_opts=opts.LabelOpts(is_show=False))
)
line.render_notebook()

      

      图中蓝色曲线为负样本占比曲线,红色曲线为KS曲线;

1. 模型在第8箱的位置出现了波动,即第8箱的负样本占比高于第7箱;

2. 虽然曲线图中有多处波动,但幅度不大,总体趋势较为平稳;

3.  因此模型的排序能力仍可被业务所接受。

      6. 评分映射

def score(fea1, fea2):
    xbeta = fea1*2.48 + fea2*4.44
    score = 900-50*(xbeta)/math.log2((1-xbeta)/xbeta)  # 基准分 + 系数 * 2^(1-p/p)
    # xbeta = model.predict_proba(evl_x)[:,1]
    # score = 600+50*math.log2((1-xbeta)/xbeta)  #好人的概率/坏人的概率
    return score

val['score'] = val.apply(lambda x: score(x.fea1,x.fea2), axis=1)
fpr, tpr, _ = roc_curve(val_y, val['score'])
ks = abs(fpr-tpr).max()

      7. 划分评级

      可以通过分数段对客群进行划分,得到每一个级别用户的逾期率。

def level(score):
    level = 0
    if score <= 600:
        level = "D"
    elif score <= 640 and score > 600 :
        level = "C"
    elif score <= 680 and score > 640:
        level = "B"
    elif score > 680 :
        level = "A"
    return level

val['level'] = val.score.map(lambda x: level(x))
val.level.groupby(val.level).count()/len(val)

      如果希望某个区间的逾期率更大或者更小,可以调整评分映射函数中的基础分和系数。

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值