本文用于内部评分卡建模分享,包括以下几个方面:
一. 样本选择
二. 特征工程
三. 模型选择
四. 结果保存
五. 其他想法
六. 总结
评分卡建模流程可以参考:
-
坏样本不够:由于业务发展等原因,刚开始数据量可能不足以支持建模,可以选择使用先专家模型。等到沉淀了一定的数据量,再进行独立的模型开发。当总的数据量足够时,也需要保证坏样本的数量超过一定数量,确保模型的稳定性。假如坏样本数量不够,也可以使用一些方法来获取更多的坏样本,例如:更改坏样本的定义,覆盖更多客户;人工通过相关黑信息关联找出来的标记样本。
-
样本有偏:举个例子说明:假如你发现坏客户符合某些聚集特征,你指定策略1进行打击后,这一类坏客户被控制,以后的坏客户都不具备这样的聚集特征。如果你的坏样本的收集时间在策略1上线之后,这个时候模型训练的结果极有可能出现满足聚集特征的风险低,不满足聚集特征的交易反而风险高,也就是说聚集特征的权重是负数。这时候模型的解释性出了问题,这个也是模型训练中一个过拟合问题的范畴。为了有效解决这个问题,可以根据业务经验来查看模型中变量的权重是否与经验相悖,如果相悖,需要仔细评估。对于是样本有偏带来的问题,可以通过重新加入符合某些条件的样本来弥补。对于这些弥补的样本获取方法一种可以从拦截样本中选择,一个可以根据经验来人工生成样本。
-
样本不平衡:谈谈模型的不平衡学习。风控模型学习是个典型的不平衡学习问题,他同时具备不平衡学习领域两个问题:(1)正负样本比率悬殊,但是正负类样本都足够多;(2)正样本样本个数也很稀少。第一个问题是基本满足样本在特征空间的覆盖情况,只是比率较大导致某些学习模型应用会出现问题。第二个问题是样本太少,导致样本在特征空间的覆盖很小,极容易过拟合,不能覆盖特征空间和对欺诈场景的覆盖。对于第二个问题,最好的方法还是先收集样本+一些不平衡学习方法。对于正负样本的比率问题,有的用1:1,有的人用1:10,有的说是1:13.这些大多都是经验。其实,对于比率这个问题,说到底就是负样本该采样多少的问题。我觉得只要保证负样本也尽可能多满足覆盖特征空间就好,因为很多负样本(好的交易样本)模式都是很相似的,对于相似的模式不用保留太多的样本。但是本来正样本就少,如果负样本和正样本一样多,我个人认为随机采样的负样本覆盖的特征空间会很小,所以,我个人不是很赞同1:1的比率。
-
拒绝推论:为了防止申请样本的可能偏误,进而还原申请客户的真实分布情形。方法:1.所有拒绝件都当做坏样本;2.根据现有放款客户的逾期做推论;3.根据模型分区对应的好坏比做推论。
-
分群分析:分群分析的主要目的在于寻找一适当的样本分群方式,将合格样本区分至各个分群后,分别开发个别的评分模型。分群分析主要可采取以下两种方式:
1)业务需求 (Business Sense)
乃依实际业务作业流程或历史经验法则先行找出可能之分群方式,之后再藉由统计分析结果验证是否为有意义的分群。2)统计预测力 (Predictive Power)
乃纯粹利用统计分析模块进行如判定树 (Decision Tree)及群集分析(Cluster) 等,藉此找出对绩效指标有预测意义的分群变量。
特征工程包括特征衍生、特征预处理、特征筛选等过程。
-
特征衍生
特征衍生 -
常见的一些特征预处理方法:
-
缺失值填充:特征的缺失值填充前,我们需要先统计特征的缺失值比率。采用某个特征来区别正常交易和异常交易前,这个特征的缺失值比率不能超过一定的阈值。对于缺失值填充的常用方法有:均值,中值,0值等。
-
异常值处理:可能由于某些原因,导致系统在收集样本时候,出现错误,特征值过大或者过小。当然,这个可能本来数据就是这样,但是,我们也需要做个处理。常用的方法:设置分位点做截断,比如0.1%,99.9%分位点等。如果对特征做了离散化处理(分箱处理),变相也是做了异常值处理。
-
连续特征归一化处理:对于连续特征,比如用户的注册时间间隔,原来的值范围各自不同,不在统一的尺度。有的连续特征值范围大,有的连续特征值范围小。如果不做归一化处理,连续特征中值范围的大的特征会淹没值范围小的连续特征对模型的影响。所以,有必要对连续特征做归一化处理。常用的连续特征归一化处理方法:(1)min-max方法;(2)z-score方法。对于互联网数据,很多特征呈现长尾power-law分布,所以,大多场景针对这种情况在做min-max 或者z-score之前,会对连续特征先做log(x)变换。
-
连续特征离散化处理:相对连续特征归一化处理,还可以对连续特征进行离散化处理。在logistic regression中,大家经常会把连续特征做离散化处理,好处: (1)是避免特征因为和目标值非线性关系带来的影响;(2)离散化也是种给lr线性模型带来非线性的一种方法;(3)方便引入交叉特征;(4)工程实现上的trick。常见的离散化处理手法:非监督的方法和监督的方法。非监督的方法:等宽,等频,经验,分布图划分等。监督方法:基于信息增益或卡方检验的区间分裂算法和基于信息增益或卡方检验的区间合并算法等。 在风控采用lr模型的时候,对于连续特征采用离散化处理会有个这样的问题:因为我们的坏样本是针对过去的欺诈场景的,欺诈手法在长期博弈中不断升级。我们不仅要让模型尽可能多的覆盖过去的欺诈手法,对未来产生欺诈对抗有一定的适应性,不至于失效太快。采用离散化处理后,就可能出现很大的跳变性。假设我们过去的的坏样本都是刚注册不久的用户,那注册时间间隔做离散化处理时候,就可能分为A,B两段,离散化处理后可以看成0-1二值变量,落在A段为1,否则为0。为1时候风险高,权重为正值。如果这个变量在过去对正负样本区分度很高,可以看成核心变量的话,那如果骗子绕过A段,跳到B段的话,对模型的预测能力衰弱会是致命的。
- 特征筛选常用的方法:
-
信息值:information value,简称IV值;IV值越大,重要程度越高。
-
信息增益:information gain;是采用信息熵的方法,信息增益表示信息熵的变化, 增益越大,说明特征区分度越明显。
-
前向后向选择,依赖模型,通过AIC或者BIC来选择最优特征集合。
-
基于其他分类模型的特征选择。
-
基于业务的选择方法:1.字段是否容易获取。2.字段获取渠道是否稳定。3.字段本身是否足够稳定。
风控的意图,简单来说就是排除坏人和挑出好人,也就是一个二分类问题。
首先,既然是二分类问题,我们就有很多的模型可以选择。以小额贷款为例。因经常需要给客户不予以贷款的缘由,故对模型的可解释性要求比较高,通常会选择逻辑回归模型、决策树模型等模型。
而在该领域内的数据竞赛中,高分选手最常用的模型是:特征工程+ XGBoost,LightGBM,GBDT+ 集成。大量的实践比赛已证明这三个模型的效果非常理想,若进步加权集成,效果将更加显著,远胜Kmeans、Logistic Regression、SVM等老牌模型。几乎所有的非图像、文本的数据竞赛领域的获奖选手都会使用。
其次,虽然是做简单的二分类,但是依然可以根据用途来挑选不同的模型。
以logistic为例,简单介绍一下相关的python包:
-
statsmodels 统计建模和计量经济学工具包。
在我自己的建模过程中,主要是使用statsmodels中的Logit模块进行特征筛选。
官方文档
statsmodels包含经典统计学和经济计量学的算法。包括如下子模块:
回归模型:线性回归,广义线性模型,健壮线性模型,线性混合效应模型等等。
方差分析(ANOVA)。
时间序列分析:AR,ARMA,ARIMA,VAR和其它模型。
非参数方法: 核密度估计,核回归。
统计模型结果可视化。
这里主要是关于Regression with Discrete Dependent Variable(分类回归模型)中的Logit进行模型拟合。
import statsmodels.api as sm
# Load the data from Spector and Mazzeo (1980)
spector_data = sm.datasets.spector.load()
spector_data.exog = sm.add_constant(spector_data.exog)
# Logit Model
logit_mod = sm.Logit(spector_data.endog, spector_data.exog)
print(logit_res.summary2())需要注意的是:summary需要改为summary2。否则会报错,也可以在源码中进行修改,将stats.chisqprob 改为 stats.distributions.chi2.sf。
结果:
Results: Logit
==============================================================
Model: Logit No. Iterations: 7.0000
Dependent Variable: y Pseudo R-squared: 0.374
Date: 2018-07-31 16:03 AIC: 33.7793
No. Observations: 32 BIC: 39.6422
Df Model: 3 Log-Likelihood: -12.890
Df Residuals: 28 LL-Null: -20.592
Converged: 1.0000 Scale: 1.0000
---------------------------------------------------------------
Coef. Std.Err. z P>|z| [0.025 0.975]
---------------------------------------------------------------
const -13.0213 4.9313 -2.6405 0.0083 -22.6866 -3.3561
x1 2.8261 1.2629 2.2377 0.0252 0.3508 5.3014
x2 0.0952 0.1416 0.6722 0.5014 -0.1823 0.3726
x3 2.3787 1.0646 2.2344 0.0255 0.2922 4.4652
==============================================================
目前statsmodels的模型都是用极大似然估计的,并且独立地、一致地假设分布误差。 所有分类回归模型定义相同的方法并遵循相同的结构,但有一些方法是特定于离散模型的。此外,其中包含一些特定于模型的方法和属性。
参数说明:
1.Df Model:模型自由度,模型自变量个数 。
2.Pseudo R-squared:类似调整R方,越大越好。
3.AIC :赤池信息准则(Akaike Information Criterion)是衡量统计模型拟合优良性的一种标准,由日本统计学家赤池弘次在1974年提出,它建立在熵的概念上,提供了权衡估计模型复杂度和拟合数据优良性的标准。
通常情况下,AIC定义为:
其中k是模型参数个数,L是似然函数。从一组可供选择的模型中选择最佳模型时,通常选择AIC最小的模型。
当两个模型之间存在较大差异时,差异主要体现在似然函数项,当似然函数差异不显著时,上式第一项,即模型复杂度则起作用,从而参数个数少的模型是较好的选择。
一般而言,当模型复杂度提高(k增大)时,似然函数L也会增大,从而使AIC变小,但是k过大时,似然函数增速减缓,导致AIC增大,模型过于复杂容易造成过拟合现象。目标是选取AIC最小的模型,AIC不仅要提高模型拟合度(极大似然),而且引入了惩罚项,使模型参数尽可能少,有助于降低过拟合的可能性。
4.BIC:贝叶斯信息准则(Bayesian Information Criterion)贝叶斯信息准则与AIC相似,用于模型选择,1978年由Schwarz提出。训练模型时,增加参数数量,也就是增加模型复杂度,会增大似然函数,但是也会导致过拟合现象,针对该问题,AIC和BIC均引入了与模型参数个数相关的惩罚项,BIC的惩罚项比AIC的大,考虑了样本数量,样本数量过多时,可有效防止模型精度过高造成的模型复杂度过高。 BIC的定义
其中,k为模型参数个数,n为样本数量,L为似然函数。kln(n)惩罚项在维数过大且训练样本数据相对较少的情况下,可以有效避免出现维度灾难现象。
5.Log-Likelihood:对数似然函数值
6.LL-Null:只有常数项的对数似然函数值
7.Coef:参数估计
- Std.Err:标准误差
9.z:z值
10.P>|z| :P值
11.[0.025 0.975]:置信区间
- sklearn
用于评分卡建模:from sklearn.linear_model import LogisticRegression
从sklearn中调用的模型,可以使用最优化的方法对模型的超参数进行调整。如:使用网格搜索的方法调优logistic的超参数。
def model_optimizing(x,y,model="LR"):
if model == "LR":
pipline = Pipeline([('lr',LogisticRegression(class_weight="balanced"))])
parameters = {
#C正则化的系数
'lr__penalty': ('l1','l2'),'lr__C': (0.01,0.1,10,1),'lr__max_iter':(80,150,100)}
grid_search = GridSearchCV(pipline,parameters,n_jobs=6,scoring='recall',cv=5)
grid_search.fit(x, y)
print('Best score: %0.3f' % grid_search.best_score_)
print('Best parameters set:')
best_parameters = grid_search.best_estimator_.get_params()
for param_name in sorted(parameters.keys()):
print('\t%s: %r' % (param_name, best_parameters[param_name]))
print("Grid scores on development set:")
print()
means = grid_search.cv_results_['mean_test_score']
stds = grid_search.cv_results_['std_test_score']
for mean, std, params in zip(means, stds, grid_search.cv_results_['params']):
print("%0.3f (+/-%0.03f) for %r"
% (mean, std * 2, params))
print()
return best_parameters
在建模过程中,最多的工作就是不断找样本,找特征,做处理,模型验证。保存每次的结果,不断的思考,才有可能找出最优的模型。写这点的主要原因是自己的思路比较跳脱加上比较懒,很多结果都没有保存,很多时候会做重复的工作。
还有就是,请写好自己的模型文档。
目前自己使用的评分卡文件夹:
- 数据:
- 原始数据 :保存原始数据
- 中间变量 :保存每次处理后的数据
- 入模变量 :模型对应数据
- 模型结果 :模型输出结果,每次迭代结果数据保存,以模型名+模型分命名。
- 代码:
- 数据导入
- 数据处理
- 变量选择
- 模型
- 文档:
- 模型开发文档(txt,xlsx,word)
最好是全英文,显得高级。
1.实现python模型上线和online学习。
服务器上搭一个python环境,使用flask+gunicorn上线自己的机器学习模型。
from flask import Flask,request,jsonify
import json
import preprocess
import classifier
app=Falsk(__name__)
clf=classifier.predictor()
@app.route("/get_results",methods=["Post"])
def toorrow_stock_price_prediction():
## Post:input data
price=request.form.get("price")
param3=request.form.get("param3")
data=[price,parama3]
## data preprocess
clean_data=preprocess.data_normalization(data)
## model_prediction
result=clf.predict(clean_data)
if result==True:
res="up"
else:
res="down"
response=json.dumps(res,ensure_ascii=False).encode("utf-8")
return jsonify(results=result)
2.反欺诈相关
基于图数据库的反欺诈系统,对比现有关系型数据库能更容易实现现有的一些交叉验证规则;
社交网络分析,主要用于分辨验证规则无法识别的一些欺诈团伙,需要多个数据维度。
3.NLP自然语言处理
用于集体件反欺诈中的公司名称匹配。其实也不需要模型,一些简单的判定规则就能实现,单纯觉得说NLP显得高级一点。
下面是自己的一些感想:
- 建模难度不大,只要记住:我们不是算法的创造者,我们只是代码的搬运工。做一个调包侠,已经足够应对现有的建模工作。
- 虽然是调包侠,自己动手写代码还是必须的。
- 多做项目,多学思路,多做记录。
- 不要执迷于学习更多的算法,熟悉业务,了解客户,打入黑产才是王道。