智能风控建模全流程--看这篇就够了

首先推荐博主新书,各种算法原理全涵盖,和包括金融风控的六大经典建模场景全实现:
北大出版社,人工智能原理与实践 人工智能和数据科学从入门到精通 详解机器学习深度学习算法原理

其他地方看到这篇总结(算法进阶 Author 泳鱼), 写的比较全面;因此,这里把一些重要和容易混淆地方加修改补充,以飨读者。

1. 信贷风控简介

信贷风控是数据挖掘算法最成功的应用之一,这在于金融信贷行业的数据量很充足,需求场景清晰及丰富。

信贷风控简单来说就是判断一个人借了钱后面(如下个月的还款日)会不会按期还钱。更专业来说,信贷风控是还款能力及还款意愿的综合考量,根据这预先的判断为信任依据进行放贷,以此大大提高了金融业务效率。
在这里插入图片描述

金融是极其注意防范风险的领域,其特殊性在于非常侧重模型的解释性及稳定性。业界通常的做法是基于挖掘多维度的特征建立一套可解释及效果稳定的规则及风控模型对每笔订单/用户/行为做出判断决策。

其中,对于(贷前)申请前的风控模型,也称为申请评分卡–A卡。A卡是风控的关键模型,业界共识是申请评分卡可以覆盖80%的信用风险。此外还有贷中行为评分卡B卡、催收评分卡C卡,以及反欺诈模型等等。

A卡(Application score card)。目的在于预测申请时(申请信用卡、申请贷款)对申请人进行量化评估。B卡(Behavior score card)。目的在于预测使用时点(获得贷款、信用卡的使用期间)未来一定时间内逾期的概率。C卡(Collection score card)。目的在于预测已经逾期并进入催收阶段后未来一定时间内还款的概率。
在这里插入图片描述

一个好的特征,对于模型和规则都是至关重要的。像申请评分卡–A卡,主要可以归到以下3方面特征:

1、信贷历史类:信贷交易次数及额度、收入负债比、查询征信次数、信贷历史长度、新开信贷账户数、额度使用率、逾期次数及额度、信贷产品类型、被追偿信息。(信贷交易类的特征重要程度往往是最高的,少了这部分历史还款能力及意愿的信息,风控模型通常直接就废了。)

2、基本资料及交易记录类:年龄、婚姻状况、学历、工作类型及年薪、工资收入、存款AUM、资产情况、公积金及缴税、非信贷交易流水等记录(这类主要是从还款能力上面综合考量的。还可以结合多方核验资料的真伪以及共用像手机号、身份证号等团伙欺诈信息,用来鉴别欺诈风险。需要注意的,像性别、肤色、地域、种族、宗教信仰等类型特征使用要谨慎,可能模型会有效果,但也会导致算法歧视问题。)

3、公共负面记录类:如破产负债、民事判决、行政处罚、法院强制执行、涉赌涉诈黑名单等(这类特征不一定能拿得到数据,且通常缺失度比较高,对模型贡献一般,更多的是从还款意愿/欺诈维度的考虑)

下面实战部分我们以经典的申请评分卡为例,使用的中原银行个人贷款违约预测比赛的数据集,使用信用评分python库–toad、树模型Lightgbm及逻辑回归LR做申请评分模型。

2. 模型数据和标签的定义

申请评分模型定义主要是通过一系列的数据分析确定建模的样本及标签。

首先,几个常见的金融风控的术语的说明如下:

逾期期数(M) :指实际还款日与应还款日之间的逾期天数,并按区间划分后的逾期状态。M取自Month on Book的第一个单词。(注:不同机构所定义的区间划分可能存在差异) M0:当前未逾期(或用C表示,取自Current) M1:逾期1-30日 M2:逾期31-60日 M3:逾期61-90日 M4:逾期91-120日 M5:逾期121-150日 M6:逾期151-180日 M7+:逾期180日以上

观察点:样本层面或同一批次客户刚开始贷款的时间窗口,是用于构建样本集的时间点(如2010年10月申请贷款的用户),不同环节定义不同,比较抽象,这里举例说明:如果是申请模型,观察点定义为用户申贷时间,取19年1-12月所有的申贷订单作为构建样本集;如果是贷中行为模型,观察点定义为某个具体日期,如取19年6月15日在贷、没有发生逾期的申贷订单构建样本集。

观察期:特征层面的时间窗口。构造特征的相对时间窗口,例如用户申请贷款订前12个月内(2009年10月截至到2010年10月申请贷款前的数据都可以用, 可以有用户平均消费金额、次数、贷款次数等数据特征)。可以看出,很多特征需要用到过去一段时间的统计指标,因此是一段较长时间。设定观察期是为了每个样本的特征对齐,长度一般根据数据决定。一个需要注意的点是,只能用此次申请前的特征数据,不然就会数据泄露(时间穿越,用未来预测过去的现象)。

表现期:标签层面的时间窗口,需要一段时间才能获得标签,因为借贷不是一场球赛能马上知道结果。定义好坏标签Y的时间窗口,信贷风险具有天然的滞后性,因为用户借款后一个月(第一期)才开始还钱,有得可能还了好几期才发生逾期。

在这里插入图片描述
对于现成的比赛数据,数据特征的时间跨度(观察期)、数据样本、标签定义都是已经提前分析确定下来的。因此我通常不用考虑特征和标签构建需要的繁琐步骤。但对于实际的业务来说,数据样本及模型定义其实也是申请评分卡的关键之处。实际场景里面,数据科学家一般不会有现成的数据及标签(客户好坏定义,当然公司的业务员可以提供分析结果给建模人员),模型的具体搭建和训练反而变为相对简单的事情。

确定建模的样本量及标签,也就是模型从多少的数据样本中学习如何分辨其中的好、坏标签样本。如果样本量稀少、标签定义有问题,那学习的结果可想而知也会是差的。

对于建模样本量的确定,经验上肯定是满足建模条件的样本越多越好,一个类别最好有几千以上的样本数。但对于标签的定义,可能我们直观感觉是比较简单,比如“好用户就是没有逾期的用户, 坏用户就是在逾期的用户”,但具体做量化起来会发现并不简单,因为有业务和时间考量而变得复杂起来。有两个方面的主要因素需要考量:

【坏的定义】逾期多少天算是坏客户。比如:只逾期2天算能否当作建模的坏客户?

根据巴塞尔协议的指导,一般逾期超过90天(M4+)的客户,即定义为坏客户。更为通用的,可以使用“滚动率”分析方法(Roll Rate Analysis)确定多少天算是“坏”,基本方法是统计分析出逾期M期的客户多大概率会逾期M+1期(同样的,我们不太可能等着所有客户都逾期一年才最终确定他就是坏客户。一来时间成本太高,二来这数据样本会少的可怜)。如下示例,我们通过滚动率分析各期逾期的变坏概率。当前未逾期(M0)下个月保持未逾期的概率99.71%;当前逾期M1,下个月继续逾期概率为54.34%;当前M2下个月继续逾期概率就高达90.04%。我们可以看出M2是个比较明显的变坏拐点,可以以M2+(即逾期30天以上)作为坏样本的定义。

在这里插入图片描述
有了对坏客户的定义,比如有逾期30天的行为的客户或者逾期90天行为的客户。具体选择30天还是90天根据不同的业务而定。之所以而这样去定义,是因为已经逾期一段时间的客户通常会一直逾期,直到银行必须需要对这个客户进行核销,客户进入催收阶段。很少情况下,客户已经逾期了一长段时间,比如半年,突然又开始主动还款。因此,对于模型的标签而言,为了节约时间,增加样本数量,用较少的逾期时间来定义坏客户是非常合理的。

为了举例方便,我们还是定义逾期90天以上(M4+)的客户为坏客户。
那么下一个问题是。既然需要90天来发现和定义一个坏客户,那么如果我们的样本里面有10万个客户,里面到底会有多少坏客户? 假设我们提前知道10万客户里面有3%的真正坏客户,也就是3000个。很显然者3000个坏客户不会同时开始逾期,然后我们只需要等待90天,所有坏客户就都暴露了。 如果90天内,所有坏客户不会都暴露,那么我们需要等多久才能确定这批10万客户里面的坏客户都暴露了?
这就要谈到第二个因素:
【表现期】借贷申请的时间点(即:观察点)之后要在多久的时间暴露表现下,才能比较彻底的确定所有的逾期客户。我们可以观察该批客户的累计坏客户比例,也就是逾期90天以上客户的比例。这个比例在头3个月是0,因为即使有客户从第一天开始就逾期,根据约定,我们也需要在90天后才能放下判定该客户是坏客户。从第四个月开始,累计的坏客户比例会逐渐上升,直到进入一个比较平缓的平台期。这个开始进入平台期的时间就是表现期。就是说,这一批客户里面该暴露的坏客户也就差不多都暴露完了,我们不用再浪费时间等啦。

如果我们把不同时期的客户都这样画出曲线,就能看出不同时期申请贷款或者信用卡客户的表现情况。这种分析方法是Vintage分析(Vintage在信贷领域不仅可以用它来评估客户好坏充分暴露所需的时间,即成熟期,还可以用它分析不同时期风控策略的差异等),通过分析历史累计坏用户暴露增加的趋势,来确定至少要多少期可以比较全面的暴露出大部分的坏客户。如下示例的坏定义是M4+,我们可以看出各期的M4+坏客户经过9或者10个月左右的表现,基本上可以都暴露出来,后面坏客户的总量就比较平稳了。这里我们就可以将表现期定位9或者10个月。

在这里插入图片描述
确定了坏的定义以及需要的表现期,我们就可以确定样本的标签,最终划定的建模样本:

好用户:表现期(如9个月)内无逾期的用户样本。
坏用户:表现期(如9个月)内逾期(如M2+)的用户样本。
灰用户:表现期内有过逾期行为,但不到坏定义(如M2+)的样本。注:实践中经常会把只逾期3天内的用户也归为好用户。
比如现在的时间是2022-10月底,表现期9个月的话,就可以取2022-01月份及之前申请的样本(这也称为 观察点),打上好坏标签,建模。

通过上面信用评分的介绍,很明显的好用户通常远大于坏用户的,这是一个类别极不均衡的典型场景,不均衡处理方法下文会谈到。

在这里插入图片描述
插播时间,推荐好书,一书在手万事莫愁。

在这里插入图片描述

3. 读取数据及预处理

上一节关于模型和标签的定义是实际工作中的重要环节。那么假如我们已经打好标签,接下来怎么建立模型呢?

本节用到的数据和代码下载

该数据集为中原银行的个人贷款违约预测数据集,个别字段有做了脱敏(金融的数据通常涉及个人数据)。主要的特征字段有个人基本信息、经济能力、贷款历史信息等等
在这里插入图片描述
数据有10000条样本,38维原始特征,其中isDefault为标签,是否逾期违约。

在这里插入图片描述

import pandas as pd
pd.set_option("display.max_columns",50)

train_bank = pd.read_csv('./train_public.csv')

print(train_bank.shape)
train_bank.head()

数据预处理主要是对日期信息、噪音数据做下处理,并划分下类别、数值类型的特征。

# 日期类型:issueDate 转换为pandas中的日期类型,加工出数值特征
train_bank['issue_date'] = pd.to_datetime(train_bank['issue_date'])
# 提取多尺度特征
train_bank['issue_date_y'] = train_bank['issue_date'].dt.year
train_bank['issue_date_m'] = train_bank['issue_date'].dt.month
# 提取时间diff # 转换为天为单位
base_time = datetime.datetime.strptime('2000-01-01', '%Y-%m-%d')   # 随机设置初始的基准时间
train_bank['issue_date_diff'] = train_bank['issue_date'].apply(lambda x: x-base_time).dt.days
# 可以发现earlies_credit_mon应该是年份-月的格式,这里简单提取年份
train_bank['earlies_credit_mon'] = train_bank['earlies_credit_mon'].map(lambda x:int(sorted(x.split('-'))[0]))
train_bank.head()


# 工作年限处理
train_bank['work_year'].fillna('10+ years', inplace=True)

work_year_map = {'10+ years': 10, '2 years': 2, '< 1 year': 0, '3 years': 3, '1 year': 1,
     '5 years': 5, '4 years': 4, '6 years': 6, '8 years': 8, '7 years': 7, '9 years': 9}
train_bank['work_year']  = train_bank['work_year'].map(work_year_map)

train_bank['class'] = train_bank['class'].map({'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6})

# 缺失值处理
train_bank = train_bank.fillna('9999')

# 区分 数值 或类别特征

drop_list = ['isDefault','earlies_credit_mon','loan_id','user_id','issue_date']
num_feas = []
cate_feas = []

for col in train_bank.columns:
    if col not in drop_list:
        try:
            train_bank[col] = pd.to_numeric(train_bank[col]) # 转为数值
            num_feas.append(col)
        except:
            train_bank[col] = train_bank[col].astype('category')
            cate_feas.append(col)
            
print(cate_feas)
print(num_feas)

4. 模型介绍1: lightGBM

基于GBM的模型,效果很强大,实现起来很简单,在不要求模型解释性而追求模型性能时候广泛使用。

lgb树模型是集成学习的强模型,自带缺失、类别变量的处理,特征上面不用做很多处理,建模非常方便,模型效果通常不错,还可以输出特征的重要性。

def model_metrics(model, x, y):
    """ 评估 """
    yhat = model.predict(x)
    yprob = model.predict_proba(x)[:,1]
    fpr,tpr,_ = roc_curve(y, yprob,pos_label=1)
    metrics = {'AUC':auc(fpr, tpr),'KS':max(tpr-fpr),
               'f1':f1_score(y,yhat),'P':precision_score(y,yhat),'R':recall_score(y,yhat)}
    
    roc_auc = auc(fpr, tpr)

    plt.plot(fpr, tpr, 'k--', label='ROC (area = {0:.2f})'.format(roc_auc), lw=2)

    plt.xlim([-0.05, 1.05])  # 设置x、y轴的上下限,以免和边缘重合,更好的观察图像的整体
    plt.ylim([-0.05, 1.05])
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')  # 可以使用中文,但需要导入一些库即字体
    plt.title('ROC Curve')
    plt.legend(loc="lower right")


    return metrics
# 划分数据集:训练集和测试集
train_x, test_x, train_y, test_y = train_test_split(train_bank[num_feas + cate_feas], train_bank.isDefault,test_size=0.3, random_state=0)

# 训练模型
lgb=lightgbm.LGBMClassifier(n_estimators=5,leaves=5, class_weight= 'balanced',metric = 'AUC')
lgb.fit(train_x, train_y)
print('train ',model_metrics(lgb,train_x, train_y))
print('test ',model_metrics(lgb,test_x,test_y))

上面代码结果:
在这里插入图片描述
参数的重要性展示:

from lightgbm import plot_importance
plot_importance(lgb)

在这里插入图片描述

5. 模型介绍2: 逻辑回归模型LR和评分卡模型

为什么要使用基于逻辑回归模型的评分卡模型?主要是线性,可解释性强,业务要求好满足。
LR即逻辑回归,是一种广义线性模型,因为其模型简单、解释性良好,在金融行业是最常用的。

也正因为LR过于简单,没有非线性能力,所以我们往往需要通过比较复杂的特征工程,如分箱WOE编码的方法,提高模型的非线性能力。

强烈推荐购买该书,进一步学习:
北大出版社,人工智能原理与实践 人工智能和数据科学从入门到精通 详解机器学习深度学习算法原理

下面我们通过toad实现特征分析、特征选择、特征分箱及WOE编码

5.1 特征选择

# 数据EDA分析
toad.detector.detect(train_bank)

# 特征选择,根据相关性 缺失率、IV 等指标
train_selected, dropped = toad.selection.select(train_bank,target = 'isDefault', empty = 0.5, iv = 0.05, corr = 0.7, return_drop=True, exclude=['earlies_credit_mon','loan_id','user_id','issue_date'])
print(dropped)
print(train_selected.shape)

# 划分训练集 测试集
train_x, test_x, train_y, test_y = train_test_split(train_selected.drop(['loan_id','user_id','isDefault','issue_date','earlies_credit_mon'],axis=1), train_selected.isDefault,test_size=0.3, random_state=0)

5.2 卡方分箱

# 特征的卡方分箱
combiner = toad.transform.Combiner()

# 训练数据并指定分箱方法

combiner.fit(pd.concat([train_x,train_y], axis=1), y='isDefault',method= 'chi',min_samples = 0.05,exclude=[])

# 以字典形式保存分箱结果

bins = combiner.export()

bins 

通过上面的特征分箱代码,每一个特征被离散化为各个分箱,如下。
在这里插入图片描述
接下来就是LR特征工程的特色处理了–手动调整分箱的单调性。

这一步的意义更多在于特征的业务解释性的约束,对于模型的拟合效果影响不一定是正面的。这里我们主观认为大多数特征的不同分箱的坏账率badrate应该是满足某种单调关系的,而起起伏伏是不太好理解的。如征信查询次数这个特征,应该是分箱数值越高,坏账率越大。(注:如年龄特征可能就不满足这种单调关系)

我们可以查看下ebt_loan_ratio这个变量的分箱情况,根据bad_rate趋势图,并保证单个分箱的样本占比不低于0.05,去调整分箱,达到单调性。(其他的特征可以按照这个方法继续调整)

adj_var = 'scoring_low'
#调整前原来的分箱 [560.4545455, 621.8181818, 660.0, 690.9090909, 730.0, 775.0]
adj_bin = {adj_var: [ 660.0, 700.9090909, 730.0, 775.0]}

c2 = toad.transform.Combiner()
c2.set_rules(adj_bin)

data_ = pd.concat([train_x,train_y], axis=1)
data_['type'] = 'train'
temp_data = c2.transform(data_[[adj_var,'isDefault','type']], labels=True)

from toad.plot import badrate_plot, proportion_plot
# badrate_plot(temp_data, target = 'isDefault', x = 'type', by = adj_var)
# proportion_plot(temp_data[adj_var])
from toad.plot import  bin_plot,badrate_plot
bin_plot(temp_data, target = 'isDefault',x=adj_var)

效果对比,调整前
在这里插入图片描述

调整后
在这里插入图片描述
根据上面的调整,更新分箱结果

# 更新调整后的分箱
combiner.set_rules(adj_bin)
combiner.export()

在这里插入图片描述

5.3 WOE编码

接下来就是对各个特征的分箱做WOE编码,通过WOE编码给各个分箱不同的权重,提升LR模型的非线性。

#计算WOE,仅在训练集计算WOE,不然会标签泄露
transer = toad.transform.WOETransformer()
binned_data = combiner.transform(pd.concat([train_x,train_y], axis=1))

#对WOE的值进行转化,映射到原数据集上。对训练集用fit_transform,测试集用transform.
data_tr_woe = transer.fit_transform(binned_data, binned_data['isDefault'],  exclude=['isDefault'])
data_tr_woe.head()

## test woe

# 先分箱
binned_data = combiner.transform(test_x)
#对WOE的值进行转化,映射到原数据集上。测试集用transform.
data_test_woe = transer.transform(binned_data)
data_test_woe.head()
var foo = 'bar';

5.4 训练逻辑回归模型

使用woe编码后的train数据训练模型。对于金融风控这种极不平衡的数据集,比较常用的做法是做下极少类的正采样或者使用代价敏感学习class_weight=‘balanced’,以增加极少类的学习权重。

对于LR等弱模型,通常会发现训练集与测试集的指标差异(gap)是比较少的,即很少过拟合现象。

# 训练LR模型
from sklearn.linear_model import LogisticRegression

lr = LogisticRegression(class_weight='balanced')
lr.fit(data_tr_woe.drop(['isDefault'],axis=1), data_tr_woe['isDefault'])

print('train ',model_metrics(lr,data_tr_woe.drop(['isDefault'],axis=1), data_tr_woe['isDefault']))
print('test ',model_metrics(lr,data_test_woe,test_y))

结果如下:
在这里插入图片描述

当然我们当前分析的数据集比较简单,从效果来看,基于逻辑回归的凭房卡模型和GBM模型差别不大。另一方面,可以看出为了得到较好的解释性,评分卡的工作要多得多。

5.5 评分卡模型的业务应用

利用训练好的LR模型,输出(概率)分数分布表,结合误杀率、召回率以及业务需要可以确定一个合适分数阈值cutoff (注:在实际场景中,通常还会将概率非线性转化为更为直观的整数分score=A-B*ln(odds),方便评分卡更直观、统一的应用。)

train_prob = lr.predict_proba(data_tr_woe.drop(['isDefault'],axis=1))[:,1]
test_prob = lr.predict_proba(data_test_woe)[:,1]


# Group the predicted scores in bins with same number of samples in each (i.e. "quantile" binning)
toad.metrics.KS_bucket(train_prob, data_tr_woe['isDefault'], bucket=10, method = 'quantile')

当预测这用户的概率大于设定阈值,意味这个用户的违约概率很高,就可以拒绝他的贷款申请。

在这里插入图片描述
大功告成,快来get这本好书,学习更多技能吧!
在这里插入图片描述

1. 营销获客 2. 贷前风控 2.1 贷前审查 2.2 反欺诈 2.3 风控策略 2.4 风控建模 2.5 数据管理 风控总监训练营 ......................................................................................................792 4 节课玩转信用评分卡模型....................................................................................792 如何搭建虚拟信用卡风控体系 ...............................................................................792 风控大牛手把手教你搭建企业级信用评分模型.....................................................792 2 大维度面ᨀ升催收效率....................................................................................792 3 堂课,从 0-1 掌握基于数据驱动的风险定价核心...............................................792 如何打造现金贷产品的风控体系?........................................................................792 解密 P2P 网贷备案——专家教你如何正确应对备案..............................................793 区块链的前世今生及其应用 ...................................................................................793 区块链热潮下不可不知的法律风险:法律专家权威解读区块链、代币等案例与法律 分析 .........................................................................................................................793 牌照决定生死,现金贷及 P2P 如何拿牌?............................................................793
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值