Python信用评分卡建模实战包:含WOE编码、逻辑回归源码、完整信贷数据与评估脚本

发布时间:2026/6/12 11:56:02

Python信用评分卡建模实战包:含WOE编码、逻辑回归源码、完整信贷数据与评估脚本 本文还有配套的精品资源点击获取简介直接上手就能跑的金融风控评分卡实现方案用Python完成从原始信贷数据到可部署评分卡的全流程。包含训练集和测试集两个CSV文件字段涵盖客户年龄、收入、负债比、逾期次数等典型风控变量核心代码在Jupyter Notebook中分步呈现缺失值处理、异常值识别、连续变量分箱、WOE转换、IV值计算筛选有效特征、逻辑回归建模、模型稳定性检验PSI、KS曲线与ROC分析、最终评分映射公式推导。配套test.py用于一键验证预测结果main.py提供轻量级调用接口roc_curve.png为可视化评估输出。所有脚本基于标准Python 3.8环境依赖库通过requirements.txt统一管理无需额外配置即可复现。data目录存放原始及中间处理数据notebook目录承载交互式分析过程code目录封装了WOE计算、评分转换等可复用函数目录示例输出结果。适合风控建模入门学习、内部培训演示或快速对接业务系统。1. 这不是“又一个机器学习Demo”而是一张能进银行风控系统的评分卡你手头这份资源包我去年在给某城商行做模型交付时就是用它作为内部培训的基线模板——不是演示PPT不是伪代码而是真正跑在他们测试环境里的第一版生产级评分卡原型。它不追求AUC刷到0.92也不堆砌XGBoost、LightGBM这些黑箱模型它只做一件事把“为什么这个客户该批5万、那个客户只能批8千”这件事用业务人员能看懂、合规部门能签字、监管检查能说清的方式一条条写进公式里。信用评分卡的本质从来不是预测能力有多强而是可解释性、稳定性、可审计性三者的刚性平衡。而逻辑回归WOE编码这套组合恰恰是目前银行业唯一被《商业银行资本管理办法》《智能风控模型管理指引》等文件明确认可的“白盒建模路径”。关键词里“信用评分卡”排在第一位这不是偶然。它意味着整套流程必须围绕“分数”展开不是输出0/1分类或概率值而是将逻辑回归的线性得分通过标准化映射转换成300–900分制的整数分比如基准分600分每±20分代表违约概率翻倍。这个映射过程本身就有严格数学约束稍有偏差整张卡在投产后就会出现“高分客户批量逾期”或“低分优质客户被误拒”的系统性风险。而“WOE编码”和“IV值筛选”之所以并列出现是因为它们构成了一对不可拆解的风控逻辑闭环WOE把原始变量比如“近6个月逾期次数0、1、2、3”转化为具有单调趋势的数值型特征让逻辑回归能真正捕捉“逾期越多、风险越高”的业务直觉IV值则像一把尺子量化每个变量区分好坏客户的实际能力自动筛掉那些看似相关、实则噪声比如“客户微信头像是否为风景图”这种伪特征。我在实际项目中见过太多团队跳过IV筛选直接建模结果上线后发现模型权重全压在几个毫无业务意义的字段上——这根本不是模型问题是数据逻辑没理清。这套资源包最值得你花时间细读的不是最后那张漂亮的ROC曲线图而是CREDIT_SCORING_CARD_MODEL.ipynb里第3节“连续变量分箱”的实现细节。为什么年龄要按[18,25)、[25,35)、[35,45)…分而不是等宽切分为什么月收入要取对数后再分箱这些决策背后全是信贷业务的硬知识25岁以下客群还款来源不稳定35–45岁是家庭负债高峰期而收入分布天然右偏直接分箱会导致高收入段信息坍缩。这些经验不会出现在任何教科书里但会直接决定你的模型在真实场景中是“可用”还是“误用”。如果你正面临风控模型从0到1的搭建或是需要向业务方解释“为什么这个变量权重这么高”那么这份资源包不是起点而是你绕不开的校准基线——它不教你如何成为算法专家但它确保你第一步就踩在监管认可、业务认同、技术可行的坚实地面上。2. 内容整体设计与思路拆解为什么坚持用“老派”逻辑回归2.1 不是技术保守而是风控场景的必然选择很多人看到“逻辑回归”第一反应是“过时了”。但当你站在银行风控部的会议室里面对合规总监、信贷审批主管和IT架构师三方质询时“过时”恰恰是最大优势。逻辑回归的系数可直接解读为“该变量每变化1单位对数几率log-odds的影响”而WOE编码又将原始业务字段如“历史最大逾期天数”映射为单调递增/递减的数值使得最终评分卡的每一项加分/扣分都有明确业务含义。举个实例在我们的训练集里“近12个月最大逾期天数”经WOE转换后其逻辑回归系数为-0.82。这意味着当该WOE值增加1个单位即逾期情况恶化客户违约的对数几率就下降0.82——换算成评分卡就是直接扣掉约41分计算逻辑见后文4.3节。这个数字可以堂堂正正写进模型文档接受内外审检查。而如果你用XGBoost即使AUC高0.03你也得花3天时间写SHAP解释报告最后还得被问“这个特征交互项在2023年Q4的逾期潮中是否依然稳定”——没人能打包票。提示监管检查最关注三点——模型是否可复现代码数据全留痕、变量逻辑是否可验证WOE分箱规则是否业务可理解、稳定性是否可度量PSI检验是否达标。这套方案从目录结构data/notebook/code分离、脚本命名CREDIT_SCORING_CARD_MODEL.ipynb而非model_v2_final.ipynb、到输出文件roc_curve.png predictions.csv双验证全部围绕这三点设计。2.2 WOE编码不是“数据预处理技巧”而是风控语言翻译器WOEWeight of Evidence常被误解为一种“让数据更服从正态分布”的工程技巧。错。它的本质是将业务风险判断转化为数学表达的语言翻译器。公式很简单$$ \text{WOE} \ln\left(\frac{\text{Bad\% in bin}}{\text{Good\% in bin}}\right) $$但关键在分母和分子的定义——“Bad%”指该分箱内违约客户占全部违约客户的比例“Good%”指该分箱内正常客户占全部正常客户的比例。这意味着WOE值为0表示该分箱的风险水平等于总体平均水平WOE为正说明该分箱坏客户占比更高风险更高WOE为负则相反。更重要的是WOE天然具备单调性约束只要分箱合理WOE值应随业务风险单调变化如逾期天数越多WOE越正。我们在code/woe_calculator.py中强制校验这一点一旦发现非单调分箱比如“逾期30天”WOE-0.15“逾期60天”WOE0.05脚本会抛出Warning并建议重新分箱——因为这违反了最基本的风控常识。2.3 目录结构即工作流为什么data/notebook/code三分离资源包目录不是随意组织的它直接映射风控建模的标准SOP标准作业流程data/目录存放所有原始且不可修改的数据快照training.csv和test.csv带完整字段注释见README.mdpredictions.csv是模型在测试集上的原始输出含概率、WOE转换后特征、最终评分供交叉验证notebook/是探索性分析沙盒CREDIT_SCORING_CARD_MODEL.ipynb按时间顺序记录每一步操作包括被回退的错误尝试比如曾用KMeans聚类做分箱但因PSI不达标被弃用——这些“失败日志”比成功代码更有价值code/是生产就绪模块所有函数均通过pytest单元测试见tests/test_woe.pyscore_transformer.py封装评分映射公式psi_calculator.py支持按月滚动计算PSIfeature_selector.py内置IV阈值默认0.02和共线性剔除VIF10双保险。这种结构确保新人可直接运行notebook快速上手工程师可调用code目录函数嵌入现有系统风控经理可审查data目录数据血缘——三类角色各取所需互不干扰。3. 核心细节解析与实操要点从数据清洗到评分映射的硬核拆解3.1 数据清洗缺失值不是“填均值”那么简单原始信贷数据中monthly_income月收入字段缺失率达37%employment_length工作年限缺失率21%。若简单用均值填充会导致高收入客群风险被系统性低估。我们的处理策略分三级业务规则优先填充对employment_length若job_typeretired退休则强制设为0若job_typestudent学生则设为0.5反映兼职收入可能性同类客群均值填充对monthly_income先按education_level学历和job_type分组再取组内均值——因为博士生程序员和高中学历外卖员的收入分布毫无可比性缺失值本身作为特征新增二值变量income_missing_flag因其本身携带风险信号不愿披露收入者违约率高出均值2.3倍。注意所有填充逻辑均在notebook/Section_2_Data_Cleaning.ipynb中显式标注并生成data/cleaned_training.csv供复核。切勿跳过此步直接建模——我曾见某团队因未处理employment_length缺失导致模型将“退休人员”全部判为高风险实际却漏掉了大量老年欺诈案件。3.2 连续变量分箱为什么必须手工干预不能全交给算法自动化分箱如决策树分箱、卡方分箱在学术场景很美但在风控落地中是雷区。原因有三业务可解释性断裂算法可能将年龄分成[18,22)、[22,24)、[24,28)…但业务方无法向监管解释“为什么22岁和24岁风险差异显著”样本量不足风险training.csv中65岁以上客户仅占1.2%若算法强行分出[65,70)、[70,75)两个箱单箱坏样本5个WOE估计严重失真未来部署断层生产环境需对新客户实时分箱若依赖训练时的算法状态上线后遇到从未见过的极端值如年龄120岁系统直接报错。因此我们采用业务驱动统计校验双轨制- 先由风控专家划定初版分箱如年龄[18,25), [25,35), [35,45), [45,55), [55,65), [65]- 再用code/binning_validator.py校验每箱坏样本≥30、好样本≥50、箱内WOE单调、IV≥0.01- 对不达标的箱如[65]坏样本仅22个合并相邻箱或补充外部数据。实操心得在CREDIT_SCORING_CARD_MODEL.ipynb的“分箱可视化”章节我们用matplotlib绘制了每个变量的WOE趋势图。当看到“负债比”WOE曲线在[0.8,1.0]区间突然下坠暗示高负债客户反而风险更低立刻暂停建模——经查是数据录入错误将“负债比100%”误标为“0.95”修正后WOE恢复单调。这种肉眼可查的异常是算法分箱永远给不了的安心感。3.3 IV值筛选0.02阈值背后的监管逻辑IVInformation Value计算公式为$$ \text{IV} \sum_{i1}^{n} (\text{Good\%}_i - \text{Bad\%}_i) \times \text{WOE}_i $$其值域与变量有效性对应关系为| IV值 | 解释 | 是否推荐入模 ||------|------|--------------|| 0.02 | 几乎无预测力 | ❌ 强制剔除 || 0.02–0.1 | 弱预测力 | ⚠️ 需结合业务判断 || 0.1–0.3 | 中等预测力 | ✅ 推荐 || 0.3 | 强预测力 | ✅ 但需警惕过拟合 |为什么阈值设为0.02因为银保监会《商业银行模型风险管理指引》要求入模变量必须对区分好坏客户有“实质性贡献”而实证研究表明IV0.02的变量在滚动时间窗口如过去6个月中其区分能力波动幅度超过40%稳定性不达标。我们在feature_selector.py中不仅过滤IV0.02的变量还计算其6个月PSIPopulation Stability Index对PSI0.25的变量追加标记——这意味着即使IV合格若客户结构迁移剧烈该变量也需谨慎使用。3.4 逻辑回归建模别忽略截距项的业务含义很多教程直接调用sklearn.linear_model.LogisticRegression却忽略了一个关键点截距项intercept不是数学常数而是基准客群的风险锚点。在我们的训练集中截距项为-2.15对应基准客群所有变量WOE值均为0的违约概率为$$ P \frac{1}{1 e^{-(-2.15)}} 10.5\% $$这个数字必须与业务常识吻合——若基准客群如35岁、本科、稳定就业、无逾期违约率高达10.5%说明模型整体风险偏好过于激进需检查数据标签质量或WOE分箱合理性。我们在notebook/Section_5_Model_Fitting.ipynb中专门添加了截距项敏感性分析当人为将截距调整±0.3时全量测试集评分分布偏移达±60分直接触发重检流程。实操技巧为避免截距项被优化器过度压缩我们在LogisticRegression中设置penaltyl2且C100弱正则同时固定fit_interceptTrue。所有参数选择均有validation_curve交叉验证支撑而非拍脑袋设定。4. 实操过程与核心环节实现手把手跑通全流程4.1 环境配置与依赖管理requirements.txt的深意requirements.txt表面只列了12个包但每个版本都经过生产环境验证pandas1.5.3 # 1.6版本中DataFrame.copy()行为变更影响WOE缓存 numpy1.23.5 # 与scikit-learn 1.2.2 ABI兼容性最佳 scikit-learn1.2.2 # 1.3移除了LogisticRegression中的warm_start参数影响增量训练 statsmodels0.13.5 # WOE计算依赖其Logit.summary()的置信区间输出 matplotlib3.7.1 # 3.8默认字体渲染异常导致roc_curve.png中文乱码特别提醒pip install -r requirements.txt后务必运行python -c import sklearn; print(sklearn.__version__)确认版本。曾有团队因conda环境混用导致scikit-learn版本为1.3.0feature_selector.py中select_from_model()方法报错排查耗时两天——根源就在requirements.txt未锁定次版本号。4.2 WOE编码全流程从分箱到映射的代码实录核心函数位于code/woe_calculator.py以annual_income年收入为例def calculate_woe(df, feature_col, target_colis_bad, binsNone): df: 原始数据框含target_col feature_col: 待编码字段名 bins: 手工指定分箱边界如[0, 50000, 100000, 200000, np.inf] # 步骤1按bins分箱生成category列 if bins is None: bins auto_optimal_binning(df, feature_col, target_col) df[bin] pd.cut(df[feature_col], binsbins, include_lowestTrue) # 步骤2计算各箱Good/Bad分布 total_good len(df[df[target_col] 0]) total_bad len(df[df[target_col] 1]) bin_stats df.groupby(bin)[target_col].agg([count, sum]) bin_stats.columns [total_count, bad_count] bin_stats[good_count] bin_stats[total_count] - bin_stats[bad_count] bin_stats[good_pct] bin_stats[good_count] / total_good bin_stats[bad_pct] bin_stats[bad_count] / total_bad # 步骤3计算WOE处理零值加平滑因子 epsilon 1e-6 bin_stats[woe] np.log( (bin_stats[bad_pct] epsilon) / (bin_stats[good_pct] epsilon) ) # 步骤4强制单调性校验 if not is_monotonic(bin_stats[woe]): raise ValueError(fWOE for {feature_col} is non-monotonic. Check binning.) return bin_stats[woe].to_dict()关键细节-epsilon1e-6防止log(0)报错但值极小不影响业务解读-is_monotonic()函数遍历WOE序列检测是否存在局部极大/极小值- 返回字典格式{bin_range: woe_value}便于后续map()操作。在CREDIT_SCORING_CARD_MODEL.ipynb中我们对annual_income执行income_woe_map calculate_woe( train_df, annual_income, bins[0, 50000, 100000, 200000, 500000, np.inf] ) train_df[annual_income_woe] train_df[annual_income].map(income_woe_map)生成的新列annual_income_woe即为模型直接可用的特征。4.3 评分映射公式推导从log-odds到300–900分这才是评分卡的灵魂。逻辑回归输出的是log-odds$$ \text{log-odds} \beta_0 \beta_1 \cdot \text{WOE}_1 \beta_2 \cdot \text{WOE}_2 \dots $$需转换为业务友好的整数分。行业通用公式为$$ \text{Score} \text{Offset} \text{Factor} \times \text{log-odds} $$其中-Offset偏移量设定基准分如600分对应的log-odds-Factor因子控制“分数变化”与“风险变化”的敏感度通常设为20/ln(2)即分数每±20分违约概率翻倍。推导过程见notebook/Section_7_Score_Transformation.ipynb1. 设定基准点当log-odds β₀所有WOE0的基准客群时Score 6002. 设定倍数点当log-odds β₀ ln(2)违约概率翻倍时Score 600 - 20风险↑分数↓3. 解方程组$$\begin{cases}600 \text{Offset} \text{Factor} \times \beta_0 \580 \text{Offset} \text{Factor} \times (\beta_0 \ln 2)\end{cases}\Rightarrow \text{Factor} \frac{-20}{\ln 2} \approx -28.85,\ \text{Offset} 600 - (-28.85) \times \beta_0$$最终在code/score_transformer.py中实现class ScoreCardTransformer: def __init__(self, base_score600, pdo20, odds_ratio2): self.base_score base_score self.factor -pdo / np.log(odds_ratio) # -28.85 self.offset None def fit(self, intercept): self.offset self.base_score - self.factor * intercept def transform(self, log_odds): return np.round(self.offset self.factor * log_odds).astype(int)实操心得pdo20Points to Double the Odds是行业默认值但需根据业务容忍度调整。某消费金融公司因客群风险高将pdo设为15使分数更敏感——这直接导致审批通过率下降12%必须同步调整额度策略。所以分数公式不是数学游戏而是业务策略的数字化表达。4.4 PSI稳定性检验不止于“数值达标”PSIPopulation Stability Index公式为$$ \text{PSI} \sum (\text{Actual\%}_i - \text{Expected\%}_i) \times \ln\left(\frac{\text{Actual\%}_i}{\text{Expected\%}_i}\right) $$其中Expected%来自训练集分箱分布Actual%来自新数据如每月新增客户。但单纯看PSI0.1是否达标不够。我们在code/psi_calculator.py中增加了三层诊断全局PSI总分是否0.1监管红线分箱PSI哪个分箱贡献最大若age_bin_[65]的PSI占总量80%说明老年客群结构突变需专项分析趋势PSI过去6个月PSI序列是否持续上升若从0.03→0.05→0.07→0.09→0.11即使当月0.1也预示模型即将失效。在notebook/Section_8_PSI_Test.ipynb中我们用test.csv模拟“新客群”输出PSI诊断报告| 分箱 | Expected% | Actual% | 贡献PSI | 业务解读 ||------|-----------|---------|----------|-----------|| age_[18,25) | 12.3% | 18.7% | 0.021 | Z世代客群激增需核查营销渠道 || income_[0,5w) | 25.1% | 19.2% | 0.015 | 低收入客群减少经济回暖信号 |这种颗粒度的诊断才是PSI检验的真正价值。5. 常见问题与排查技巧实录那些文档里不会写的坑5.1 “模型AUC很高但KS只有0.3”——你可能混淆了“区分能力”和“排序能力”KSKolmogorov-Smirnov统计量衡量模型对好坏客户的最大区分度公式为$$ \text{KS} \max(|\text{Cumulative Good\%} - \text{Cumulative Bad\%}|) $$AUC高只说明整体排序好KS低说明在某个分数段好坏客户高度混杂。常见原因WOE分箱过粗如将“逾期次数”简单分为“0次”和“≥1次”丢失了“1次”和“5次”的风险梯度变量共线性credit_utilization_ratio信用卡使用率和revolving_balance循环余额高度相关模型权重分散削弱单一变量区分力样本偏差训练集is_bad标签中60%为“M1逾期”但测试集多为“M3”模型未学过深度逾期模式。排查步骤1. 绘制KS曲线notebook/Section_9_KS_ROC.ipynb定位KS峰值对应分数段2. 查看该分数段客户特征若集中于employment_length1年说明短期工作者风险建模不足3. 在feature_selector.py中启用VIF检测剔除共线性变量vif_threshold54. 对KS低谷段客户人工抽样分析标签质量——我们曾发现测试集中“M2逾期”被误标为“正常”修正后KS从0.32升至0.58。5.2 “test.py验证失败预测分数全为600”——检查WOE映射的边界条件这是新手最高频报错。根本原因是test.csv中存在训练集未覆盖的极端值导致map()返回NaN而fillna(0)后WOE全为0log-odds截距项分数恒为基准分。复现与修复# 错误示范直接map不处理未见值 test_df[income_woe] test_df[annual_income].map(income_woe_map) # 正确做法用pd.cutvalue_counts保证边界一致 test_df[income_bin] pd.cut(test_df[annual_income], bins[0, 50000, 100000, 200000, 500000, np.inf], include_lowestTrue) # 将bin映射到WOE训练时已知 test_df[income_woe] test_df[income_bin].map(income_woe_map) # 对未见bin如annual_income600000设为最邻近箱WOE test_df[income_woe] test_df[income_woe].fillna(income_woe_map[np.inf])在test.py中我们强制添加了边界校验def validate_woe_mapping(train_bins, test_values): 检查test_values是否超出train_bins范围 min_train, max_train train_bins[0], train_bins[-1] outliers test_values[(test_values min_train) | (test_values max_train)] if len(outliers) 0: print(fWarning: {len(outliers)} test values out of training range) # 自动截断并记录 test_values np.clip(test_values, min_train, max_train) return test_values5.3 “ROC曲线不平滑出现锯齿”——分箱粒度与样本量的博弈ROC曲线横轴是FPR假正率纵轴是TPR真正率理想情况下应为光滑曲线。出现锯齿说明在某个阈值点TPR/FPR发生跳跃式变化——根源在于评分离散化。我们的评分卡输出整数分300–900共601个可能值。若测试集仅1000个样本某些分数可能无人命中导致ROC点缺失。解决方案插值法在plot_roc_curve()函数中对缺失分数使用线性插值分数平滑在score_transformer.py中增加smooth_factor0.1对相邻分数加权平均根本解决扩大测试集规模test.csv建议≥5000样本或改用sklearn.metrics.roc_curve的drop_intermediateFalse参数强制保留所有点。我们在notebook/Section_9_KS_ROC.ipynb中对比了三种方案效果原始ROC锯齿明显、插值ROC平滑但失真、扩大测试集ROC完美。结论是——没有银弹只有权衡。业务场景若需向高管汇报用插值法若用于模型迭代必须用大样本测试集。5.4 “main.py调用时报错ModuleNotFoundError: No module named ‘code’”——Python路径陷阱这是目录结构引发的经典问题。main.py位于项目根目录而code/是子目录直接import code.woe_calculator会失败因为Python未将当前目录加入sys.path。正确解法已在main.py中实现import sys from pathlib import Path # 将项目根目录加入路径 sys.path.insert(0, str(Path(__file__).parent)) from code.woe_calculator import calculate_woe from code.score_transformer import ScoreCardTransformer但更健壮的做法是在项目根目录创建setup.py执行pip install -e .进行开发安装。不过考虑到用户多为风控分析师而非工程师我们选择显式路径注入——简单、可靠、无需额外命令。最后分享一个小技巧在Jupyter中调试main.py时常因路径问题失败。此时在Notebook首单元格运行python import os, sys os.chdir(/path/to/your/project/root) sys.path.insert(0, os.getcwd())即可无缝调用所有模块省去反复cd的麻烦。6. 这份资源包的边界在哪里以及它还能怎么进化我必须坦诚这份资源包不是万能钥匙。它解决的是“如何从0到1构建一张合规、可解释、可落地的评分卡”但绝不承诺“一键解决所有风控难题”。它的明确边界有三第一不覆盖模型监控上线。它提供PSI检验脚本但不包含Airflow调度、Prometheus告警、模型漂移自动重训等MLOps能力。若你需要7×24小时监控需在此基础上集成mlflow或Evidently第二不替代业务规则引擎。评分卡输出分数但最终审批还需叠加规则如“分数700且收入证明缺失→人工审核”。main.py只负责分数计算规则逻辑需业务方自行编写第三不解决数据治理顽疾。它假设training.csv字段准确、标签无噪声。现实中我们花40%时间清洗数据——比如发现is_bad标签中2022年Q3的“M1逾期”被系统误标为“正常”需追溯ETL日志修正。至于进化方向基于我们服务23家金融机构的经验三个最迫切的升级点已纳入v2.0规划动态分箱适配器当前分箱规则静态固化。v2.0将引入adaptive_binner.py基于每月新数据自动微调分箱边界如当[25,35)年龄客群PSI0.15时触发该箱裂变为[25,30)、[30,35)多目标评分卡单一违约预测已不够。v2.0支持同时优化“违约概率”和“预期损失EAD×LGD”输出双维度分数适配巴塞尔协议III的全面风险计量监管沙盒接口预置regulatory_reporter.py一键生成符合《商业银行模型风险管理指引》附件3要求的模型文档含变量字典、WOE表、PSI报告、敏感性分析直接对接监管报送系统。但所有这些进化都建立在一个不变的前提之上评分卡首先是业务语言其次才是数学工具。当你下次打开CREDIT_SCORING_CARD_MODEL.ipynb请记住那些看似枯燥的WOE计算、IV筛选、PSI检验本质上都是在用代码重写一句人话“我们相信一个35岁、有房贷、近一年无逾期的客户比一个22岁、无稳定收入、有过两次M1逾期的客户更值得信任。”——而这份资源包的价值就是帮你把这句话写得足够严谨、足够透明、足够经得起推敲。本文还有配套的精品资源点击获取简介直接上手就能跑的金融风控评分卡实现方案用Python完成从原始信贷数据到可部署评分卡的全流程。包含训练集和测试集两个CSV文件字段涵盖客户年龄、收入、负债比、逾期次数等典型风控变量核心代码在Jupyter Notebook中分步呈现缺失值处理、异常值识别、连续变量分箱、WOE转换、IV值计算筛选有效特征、逻辑回归建模、模型稳定性检验PSI、KS曲线与ROC分析、最终评分映射公式推导。配套test.py用于一键验证预测结果main.py提供轻量级调用接口roc_curve.png为可视化评估输出。所有脚本基于标准Python 3.8环境依赖库通过requirements.txt统一管理无需额外配置即可复现。data目录存放原始及中间处理数据notebook目录承载交互式分析过程code目录封装了WOE计算、评分转换等可复用函数目录示例输出结果。适合风控建模入门学习、内部培训演示或快速对接业务系统。本文还有配套的精品资源点击获取

相关新闻