目录
样本选择
样本选择是指从业务数据中选择部分合适的样本进行模型开发。在业务开展较长时间后数据量可能变得很大,此时,我们一般不会使用全体历史样本,而是选择能够代表总体的部分样本建模。风控模型是一种预测模型,保证预测模型良好效果的前提是客户未来的行为和过去相似,这样才可以从过去的数据中学到规律并预测未来的表现。因此,选取的建模样本能否有效代表总体,建模样本中提取的信息(一般指特征的预测能力)能否延伸到未来,将在很大程度上决定最终模型的效果。
样本选取需要把握的重要原则是“建模样本必须能够代表总体,与未来模型使用场景下的样本差异尽可能小”,具体体现为以下4点。
代表性
代表性主要是指客群的代表性。由于不同客群间客户行为具有差异,为了使建模样本能够代表总体,选取的建模样本需要能够反映未来使用场景的客群性质。例如,历史上有多种期限的产品,而未来主要以某一种期限的产品为主,那么我们最好选取未来期限的产品样本来建模。对于有多个子类别的客群,为了保持代表性,可采用分层采样方式,保证每个重要类别的对象都在样本中拥有足够的比例。
充分性
充分性主要是指样本的充分性。样本太少,可能无法反映客户群体携带的内在信息,无法满足统计的显著性要求。风控建模时,要求坏样本数不能太少,至少上于条,否则模型效果难以保证。当坏样本占比较小时,我们可以考虑通过上采样方式扩充坏样本数。
在信贷风控领域,如果建立信用评分模型,那么数万条祥本已经可以做出比较可靠的摸型。更大的样本量一般能够提升模型的效果和稳定性。但是,样本量并非越大越好,因为当样本量达到一定程度,已经可以从样本中充分提炼出具有代表性的数理关系时,若再增加样本量,那么对模型效果的提升微乎其微,反而消耗更多的资源。
时效性
在已满足建模样本的充分性要求后,我们应尽量选取近期样本,即样本的产生时间越近越好。时间越久远,数据越陈旧,可能造成与未来使用场景下的样本的差异较大。对于银行等客群相对稳定的机构,长久之前的样本对时效性的影响不大。但是,对于客群变化较大的信贷平台,我们就需要对时效性的影响进行重点关注。
排除性
建模样本除需要满足客群的代表性,以及样本的充分性和时效性以外,还应在选取样本时排除某些因政策调整、不可控因素导致的客群质量异常样本。例如,某工厂在3月因某种原因停产,导致这段时间在某信贷产品上的逾期率显著升高,到了4月,该工厂恢复生产,逾期率也恢复到了正常水平。因此,在选取建模样本时,我们应将排除3月的样本作为一种实验方案,因为这段时间客户逾期行为受某种因素的影响较大。
需要注意的是,我们是在放款样本上选取的建模样本,而未来模型的使用场景会在全量申请样本上,因此,存在“部分样本估计总体”问题,对全量申请客户的风险估计就不准确。
多进行对比实验。尽管我们给出了样本选择的一般性原则,但在实践中,我们建议,在有条件的情况下,对不同的样本组合进行尝试,原理上最优并不代表实际上最优。我们经常面临样本量和样本质量的权衡与取舍,它们之间的平衡点在哪里,除非将各种组合都尝试一遍,否则无法知晓。
样本集划分
数据是模型搭建的基础。在模型开发过程中,我们通常会划分一部分数据用于训练模型,并将另一部分数据用来验证模型效果。
training set(训练集)、validation set(验证集)和testset(测试集)的定义。训练集用来训练模型,验证集用来模型调参、训练过程中的参数选择或者模型选择,测试集用来验证模型最终表现。在风控模型中,我们通常将靠近当前时间段的样本作为测试集,特别地称为OOT样本(OutofTime sample,时间外样本),以确保建模和验证数据时间不重叠,准确地衡量模型预测能力。
训练集和验证集的样本时间范围是对齐的。OOT样本的划分比例根据样本总量、业务需求确定,一般为10%~20%。同时,需要确保OOT样本量不能太小,应该特别关注“坏样本”的数量,其最好大于100个,否则无法准确评估模型效果。然后,可将其余祥本作为建模样本,划分为训练集和验证集。
特别地,在样本较少的情况下,为了让更多的样本参与模型训练,可以将验证样本取消,保留训练样本和OOT样本,建模时,训练样本上采用交叉验证的方式进行模型参数选择。在样本更少的极端情况下,先用个述方法获得初代模型,再用相同的模型参数在合并的训练样本和OOT样本上重新训练最终模型,当然,这种方法已经较难准确评估模型效果了。但是,这是在特殊情况下获得一个更好的模型的备选方法,至少可以作为“陪跑”(不参与决策)模型上线试一试。我们以德国信用卡数据集为例,说明代码实现过程。由于德国信用卡数据集没有时间列,因此,我们随机添加表示时间的列“month”,产生包含月份列的数据。参考代码如下
import scorecardpy as sc
def get_data();
#导入原始数据集
german credit data = sc.germancredit()
german_credit_data[label] = np.where(german_credit_data[label] == 'bad' , 1,0)
np.random.seed(0)
month_list = ['2020-01','2020-02','2020-03','2020-04','2020-05']
#随机分配月份
german_credit_data['month']=np.random.choice(month_list, len(german_credit_data))
return german_credit_data
上述代码首先从scorecardpy包中导入原始数据集,然后设置随机数种子,确保每次运行代码的结果相同,最后利用NumPy库中的random.choice()函数从month_list列表内给每个样本随机赋值,产生“month”列。我们可将上述功能封装在函数get_data()中,然后将其存储在代码库的 utils文件夹的prepare_data.py脚本内,方便后续调用。
我们将2020年5月份样本作为OOT样本,将1~4月份样本作为训练样本和验证样本,并按照7:3的比例划分训练集和验证集,参考代码如下
from utils import datautils
from sklearn.model_selection import train_test_split
#导入添加month列的数据
model_data = datautils.get_data()
oot_set = model_data[model_data['month'] =='2020-05']
train_validset = model_data[model_datal['month']] != '2020-05']
X= train_validset[data_utils.x_cols]
Y= train_validset['creditability']
X_train, X_valid, Y_train, Y_valid = train_test_split(x, Y,random_state=88)
model_data.loc[oot_set.index,'sample_set']='oot'
model_data.loc[X_train.index,'sample_set']='train'
model_data.loc[X_valid.index,'sample_set']='valid
print('每天都要开心啊')