简介:面向金融风控与信贷场景的Python申请评分卡模型数据集,聚焦于利用application.csv构建申请评分卡,适合数据挖掘学习者与金融领域从业者快速掌握信用风险评估建模流程。压缩包共14个文件,涵盖pkl模型对象、Python脚本、原始CSV数据集及lr_classweight辅助文件,模型与脚本相互配套,覆盖从数据清洗、特征选择、逻辑回归训练到WOE分箱与评分卡生成的完整链路。资源大小约9.22MB,已有1695人学习下载。除可直接使用的训练好的LR模型与WOE编码字典外,还提供分箱合并结果、评分卡核心函数及GBDT、DNN等对比模型脚本,帮助读者理解不同算法在申请评分卡中的应用,并结合测试脚本验证模型效果,快速复现完整建模过程,降低从理论到实践的门槛。 做申请评分卡,数据集怎么选、怎么洗、怎么用,往往比调模型参数更费心思。作为入门风控建模最常见的一道坎,很多人一上来就到处找数据集,结果找到的不是字段太脏就是坏样本比例失真,练完发现跟真实业务完全是两码事。这篇文章我把整个流程里跟数据集强相关的关键环节拆开讲,从选数据、做分箱、算WOE/IV,到逻辑回归训练和评分刻度化,每一步附上可直接参考的做法和踩坑记录,希望能让刚开始接触这块的朋友少走弯路。
1. 项目整体设计:申请评分卡到底在解决什么问题
1.1 核心需求解析
申请评分卡(Application Scorecard)是信贷风控场景里应用最广的模型之一,核心任务是根据申请人提交的信息(年龄、收入、负债、学历、历史还款记录等),预测其在未来一段时间内发生逾期或违约的概率。和机器学习里常见的CTR预测、图像分类不同,评分卡模型有一个很明确的产品化要求:输出必须是一个整数分数,比如650分、720分,并且这个分数要能解释给业务人员听——为什么这个人能过、那个人被拒绝,理由必须站得住脚。这也是为什么工业界做评分卡首选逻辑回归而不是XGBoost,虽然树模型精度往往更高,但可解释性和监管合规性都很难达标。
从技术链路上看,评分卡建模通常包括:
- 数据获取与探索性分析(EDA)
- 数据清洗与样本划分
- 特征分箱与WOE编码
- IV值筛选特征
- 逻辑回归训练
- 评分刻度化(Scorecard Scaling)
- 模型评估与上线监控
其中,特征分箱和WOE编码是评分卡区别于其他模型最核心的环节,也是数据集质量对结果影响最大的地方。很多人拿到数据集直接塞进逻辑回归,发现AUC很低、系数符号还反了,问题通常就出在数据预处理和分箱策略上。
1.2 数据集选型的关键考量
做评分卡最理想的数据当然是真实的信贷审批数据,包含放款后的表现标签(比如逾期90天以上记为坏样本)。但真实数据涉及隐私和合规,网上能公开获取的数据集并不多。常见的替代方案有这几个:
- UCI German Credit Dataset:1000条样本,20个特征,坏样本比例30%,经典但样本量小,适合入门练手
- UCI Statlog (Australian Credit Approval):690条样本,混合类型特征,有缺失值,适合练习清洗流程
- Lending Club Loan Data:样本量大,几十万条,字段丰富,适合验证特征工程的威力,但需要自己定义好坏样本,且数据时间跨度大,要注意风险政策漂移问题
- 台湾某银行信用卡违约数据集(UCI Credit Card Default):30000条样本,23个特征,违约率约22%,工业界入门最常用的一个
我在入门阶段推荐从台湾信用卡数据集入手,理由很简单:样本量适中、特征含义明确、坏样本比例真实、不需要处理太复杂的文本或时序字段,能让你把注意力集中在分箱和WOE逻辑上,而不是一开始就被脏数据劝退。
注意:Lending Club数据虽然量大,但它的坏样本定义(比如逾期15天就算坏)和国内主流信贷业务的定义差别很大,用它练出来的模型不能直接套到国内场景,这点心里要有数。
2. 数据集预处理与特征分箱:评分卡的灵魂环节
2.1 缺失值与异常值处理的实操标准
拿到数据集第一件事不是标准化,也不是One-Hot,而是先看缺失率和分布。评分卡场景里,缺失值本身往往就携带信息——比如申请人没填工作单位,可能意味着收入来源不稳定。所以我不建议直接用均值填充或删除缺失行,更推荐的做法是单独把“缺失”作为一个类别,参与后续分箱。
以台湾信用卡数据集为例,它本身缺失值很少,但很多字段存在“0值”的极端情况。比如每月还款金额为0,不一定是真没还款,可能是数据采集问题,也可能意味着该用户当月没有账单。这类业务含义明确的字段,要结合实际情况决定是当作异常值剔除,还是保留为一个独立分箱。
异常值处理上,我习惯采用分位数截断。比如年龄字段,真实业务里申请人年龄一般集中在18到65岁,如果出现200岁这种明显错误值,直接截断到上下1%分位数即可。千万不要在分箱之前做Z-Score标准化,因为评分卡要求的是业务可解释的分箱边界,而不是一个抽象的标准分。
2.2 分箱策略:等频、等距与卡方分箱怎么选
分箱是把连续变量切成若干区间,比如把“年龄”分成 [18,25)、[25,30)、[30,40)、[40,50)、[50,65] 五段。分箱的目的有两个:一是捕捉非线性关系,比如年龄和违约率是典型的U型曲线,年轻人和老年人违约率高,中年人最低,这个逻辑回归直接拟合年龄数值是拟合不出来的;二是让模型对异常值和缺失值更稳健。
常见的分箱方法有三种:
- 等距分箱:按区间宽度相等切分,比如收入从0到100万,每隔10万一箱。缺点是样本分布不均匀,很多箱子里样本量极少,WOE估计不稳定
- 等频分箱:按样本量均等切分,每箱样本数差不多,稳定性好,但边界不直观。比如收入第20百分位是3500元,那这个边界就不够“业务”
- 卡方分箱(ChiMerge):自下而上合并相邻区间,使得合并后的坏样本比例差异最大化。这是工业界最推荐的方式,因为它同时考虑了样本量和目标变量的区分度
卡方分箱的落地逻辑并不复杂:先把每个唯一值当成一个初始箱子,计算相邻两个箱子的卡方统计量,如果两个箱子在好坏样本分布上没有显著差异(p值大于阈值),就合并它们,重复这个过程直到满足停止条件。实际操作中可以直接用statsmodels或scipy实现,也可以借助第三方库scorecardpy,它是R语言scorecard包的Python移植版,封装好了woebin、woe_iv、scorecard2等常用函数,非常方便。
2.3 WOE编码与IV值计算:为什么用WOE而不是原始值
WOE(Weight of Evidence,证据权重)是评分卡建模中最重要的数据转换方式。其计算公式为:
WOE_i = ln( (坏样本在该箱的占比) / (好样本在该箱的占比) )
换成更严谨的写法:对第i个分箱,令坏样本数为B_i、好样本数为G_i,总坏样本数为B_T、总好样本数为G_T,则:
WOE_i = ln( (B_i / B_T) / (G_i / G_T) )
从公式可以看出,WOE衡量的是“该箱内的坏样本相对于整体来说是多还是少”。WOE为正说明该箱坏样本比例高于整体,为负说明低于整体。把原始特征替换为WOE值再进入逻辑回归,有三个明显好处:
- 特征和Logit(对数几率)天然呈线性关系,契合逻辑回归的假设
- 处理好缺失值和极端值,因为它们都已经被并到某个箱子里
- 量纲统一,不同特征的WOE值可以直接比较
IV(Information Value,信息价值)就是基于WOE计算出来的特征重要性指标:
IV_i = (B_i/B_T - G_i/G_T) * WOE_i IV = Σ IV_i
经验规则是:IV小于0.02说明特征几乎没有预测力,0.02到0.1为弱预测力,0.1到0.3为中等,0.3以上为强。但要注意,IV过高(比如超过0.5)反而要警惕这个特征是否泄漏了目标变量,比如用“是否已经逾期”去预测“是否违约”,这就没有意义了。
3. 模型训练与评分卡刻度化:从概率到分数的换算
3.1 逻辑回归训练的要点
特征经过WOE转换后,接下来就是标准的逻辑回归训练。这里有一个容易忽略的细节:训练时用的必须是WOE值,而不是原始值或者标准化后的值,否则整个评分卡的可解释性就没了。特征的系数大小直接反映该特征的贡献方向,系数为正表示WOE越高违约风险越大,反之亦然。
训练过程中我通常会在逻辑回归里加上正则化参数。评分卡场景推荐使用L2正则,因为它能防止系数过大导致评分波动剧烈,同时不会像L1那样把特征系数压到0,保留了完整的可解释性。在sklearn中设置C=0.01或者C=0.1都是合理范围,具体值可以通过网格搜索配合交叉验证来确定。
样本不平衡也是一个绕不开的问题。比如台湾信用卡数据集坏样本比例是22%,还算正常,但如果坏样本只有3%,直接训练出来的模型会倾向于把所有样本预测为好客户。处理方法有两种:一是对坏样本做SMOTE过采样,二是调整逻辑回归的class_weight='balanced'。我个人的经验是尽量先调class_weight,因为SMOTE容易生成不真实的样本点,在信贷场景里反而引入噪声。
3.2 评分刻度化公式与参数计算
模型训练完成后,需要把逻辑回归输出的概率转换为整数分数,这一步叫评分卡刻度化。标准公式为:
Score = Offset + Factor * ln(odds)
其中odds = p/(1-p)是赔率,p为模型预测的违约概率。Offset和Factor是两个需要人为设定的刻度参数,通常用以下两个业务规则来确定:
- 设定某个特定分数(比如600分)对应的odds基准值
- 设定odds翻倍时分数增加的幅度(PDO,Points to Double the Odds)
举个例子,假设我们希望600分对应odds=50,odds每翻一倍分数增加20分(PDO=20),那么根据公式推导,可以得到:
Factor = PDO / ln(2) = 20 / 0.6931 ≈ 28.85 Offset = 600 - Factor * ln(50) = 600 - 28.85 * 3.912 ≈ 487.1
所以最终评分公式为:
Score = 487.1 + 28.85 * ln(odds)
在实际代码里,对每个样本先算出逻辑回归的线性预测值logit = β0 + Σβi*WOE_i,然后ln(odds) = logit,这样每个分箱对应一个分数贡献值。把所有特征的贡献加起来再加上基准分,就得到最终的信用评分。每个分箱的分数贡献为:
Score_i = - (βi * WOE_i) * Factor + (Offset / n_features)
具体到代码实现:在拟合好逻辑回归后,取出系数和截距,结合WOE映射表,生成一张“特征分箱-分数贡献”映射表,线上应用时直接查表累加,根本不需要跑模型推理,这也是评分卡在工程上的一大优势——快、透明、易维护。
4. 模型评估与常见问题排查实录
4.1 KS值与AUC的配合使用
评分卡模型常用的评估指标有两个:KS(Kolmogorov-Smirnov)和AUC。KS表示好样本和坏样本累计分布的最大差距,一般超过0.3就说明模型有不错的区分能力,超过0.5要警惕过拟合。我见过很多新人只盯着AUC看,其实KS在风控里更常用,因为它直接反映模型在某个分数阈值下的区分力度,和审批策略的cutoff设定更相关。
画KS曲线的方法不复杂:把预测分数从高到低排序,按等频分成10组或20组,统计每组的好样本累计占比和坏样本累计占比,两者差值的最大值就是KS。这个值通常出现在分数中段,如果最大差距出现在最高分组或最低分组,说明模型分数校准可能出了问题。
4.2 特征泄漏与时间穿越:两个容易忽视的坑
特征泄漏是数据集中最难发现的问题之一。比如你用Lending Club的数据建模,发现“贷款金额”这个特征IV值特别高,仔细一想,贷款金额是审批通过后才产生的变量,在申请时点根本拿不到。这就是典型的“未来变量”泄漏。排查方法其实很简单:每个特征都要问自己一句,这个字段在申请时点是否已经确定?如果答案是否定的,就不应该进模型。
时间穿越比特征泄漏更隐蔽。假设你的训练数据是2015到2018年的样本,测试数据是2019年的样本,但你没有去除训练集中2017年之后发放的贷款,只截取了2018年底的标签表现,那么2017年发放的贷款只有1年表现期,2015年的却有3年表现期,标签定义不一致会导致模型严重失真。正确做法是固定一个“观察点”,确保所有样本有相同的表现窗口长度。
4.3 一份常见问题速查表
| 问题现象 | 可能原因 | 排查与解决办法 |
|---|---|---|
| 模型AUC很高但KS很低 | 分数整体偏高,好坏人分数分布重叠 | 检查样本是否重复,重新划分训练/测试集 |
| 某个特征系数符号与业务常识相反 | 分箱方向反了,或特征与其它特征高度相关 | 查看该特征WOE与目标变量的单调性,考虑特征剔除 |
| 训练集表现远好于测试集 | 过拟合或时间穿越 | 加强正则化,检查是否存在未来变量 |
| 线上分数波动剧烈 | 某个特征WOE映射表不稳定 | 减少分箱数量,合并样本量过少的箱子 |
| 缺失值样本分数异常低 | 缺失值被单独分箱但样本量太少 | 对大样本分箱的WOE做矫正,或补充缺失值填充策略 |
4.4 实操过程中的三点独家心得
第一点,分箱数量不是越多越好。我见过有人把一个连续特征分成20箱,训练集KS很好看,一上线就崩。经验值是每个特征控制在5到8箱,保证每箱样本量不低于总样本的5%。如果某个箱子样本量太少,宁可手动合并,也不要让模型去拟合这一小撮人的噪声。
第二点,不要迷信IV值自动筛选。IV是单变量指标,两个IV都不高的特征组合起来可能很有区分度,反之两个IV都很高的特征可能高度相关,同时进模型反而引入共线性。我习惯用IV排序初步筛选后,再做一次相关性分析,相关系数超过0.7的两个特征只保留IV较高的那个。
第三点,评分卡的cutoff设定要结合业务成本。分数阈值不是越高越好,调高分数能减少坏账,但也会拒绝更多好客户。实操中可以用测试集画出不同阈值下的“通过率-坏账率”曲线,再结合单客利润和坏账损失估算最优阈值。这一步很多人忽略,但它才是评分卡真正产生商业价值的地方。
5. 完整代码实现与复现路径
5.1 基于scorecardpy的快速建模脚手架
如果你是第一次做评分卡,我建议直接用scorecardpy库跑通全流程,它把分箱、WOE、IV、建模、评分全部封装好了,代码量能压缩到几十行。下面是一段可以直接运行的参考代码,数据集用UCI的台湾信用卡违约数据,从这个链接可以下载到UCI_Credit_Card.csv。
import scorecardpy as sc import pandas as pd from sklearn.linear_model import LogisticRegression # 读取数据 df = pd.read_csv('UCI_Credit_Card.csv') # 目标变量:默认还款状态,2表示违约 df.rename(columns={'default.payment.next.month': 'y'}, inplace=True) # 自动分箱(卡方分箱) bins = sc.woebin(df, y='y', x=list(df.columns[1:-1])) # WOE转换 train_woe = sc.woebin_ply(df, bins) # 逻辑回归训练 y = train_woe['y'] X = train_woe.drop(columns=['y']) lr = LogisticRegression(C=0.1, class_weight='balanced', max_iter=1000) lr.fit(X, y) # 评分卡刻度化,指定基准分和PDO card = sc.scorecard(bins, lr, X.columns, points0=600, odds0=1/50, pdo=20) # 输出每个特征的分数贡献表 sc.scorecard_ply(df, card, print_step=0)代码跑完后,sc.scorecard_ply会返回每个样本的最终评分。你还可以把card打印出来,得到一份类似“年龄[18,25)字段得分-10分”的可解释映射表,这就是最终可以交付给业务或开发人员的评分卡明细。
5.2 从零手写WOE分箱的替代路径
如果不想依赖封装库,手写一个简单的等频分箱加WOE计算也不难,核心逻辑是先按分位数切分数据,再对每个箱子计算好坏样本占比。这个过程的代码量在三五十行左右,适合想彻底搞清楚底层原理的读者。
我的建议是先用scorecardpy跑通结果,再自己手写一遍,对比两者的分箱边界和IV值是否一致。一致了,就说明你对整个链路的核心逻辑是真的理解了,而不是只会调包。
6. 数据集的进阶扩展方向
当你把UCI信用卡数据集整个流程跑通之后,建议往两个方向扩展。第一个方向是增大样本量,切换到Lending Club数据,自己定义坏样本口径、自己处理时间窗口,这个过程能帮你建立“从业务到数据到模型”的全局观。第二个方向是引入特征衍生,比如把“每月还款金额/账单金额”构造成还款率,这个衍生特征往往比原始字段区分度更高,IV能从0.08直接提到0.25以上。
提示:如果以后有条件接触到真实脱敏数据,务必把数据字典和特征血缘关系整理清楚。评分卡上线后需要定期监控特征分布漂移,没有数据字典,监控脚本根本不知道每个字段的业务含义,最后只能靠人肉回忆,非常痛苦。
我个人在实际操作中对数据集部分的体会是:评分卡的建模流程相对固定,真正的差距在特征理解和数据处理习惯上。很多人一遍遍调模型参数、试各种高级算法,都没把分箱做细致,结果上线一测分数分布完全不可用。反过来,把数据分布吃透、把每个特征的好坏样本逻辑理顺,哪怕只用最简单的逻辑回归,也能产出一个经得起业务挑战的评分卡。这也是这个项目最值得花时间的地方。
本文还有配套的精品资源,点击获取