ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python机器学习贷中风险预测模型:从数据切分到评分卡实战

Python机器学习贷中风险预测模型:从数据切分到评分卡实战 简介这是一套面向计算机相关专业学生与项目实战学习者的贷中风险预测完整项目包以Python机器学习为核心围绕金融大数据建模赛题展开适合用作毕业设计、期末大作业或技能进阶练习。资源共50个文件包含19个py脚本、11个csv数据集、5个ipynb笔记本、4个docx文档、3个xlsx表格及2个pptx答辩演示压缩包约10.83MB覆盖数据处理、特征工程、模型训练与结果输出全流程。项目已通过本地编译与严格调试确保可运行并附有赛题方案说明、数据字段解释及答辩PPT便于理解建模思路与汇报展示。模型部分涵盖决策树、随机森林、LightGBM、XGBoost、AdaBoost、朴素贝叶斯等多种算法实现特征提取环节尤其值得借鉴。目前已有62人学习适合需要完整案例参考与代码复现的读者下载使用。1. 贷中风险预测到底在预测什么从一笔已放款订单说起假设你手里有一批已经放出去的个人消费贷用户每个月都在还款。某天你发现某个客户前 6 期都正常第 7 期突然逾期了。这时候再打电话催收成本已经很高。贷中风险预测要做的就是在客户还没逾期之前用他放款后的行为数据提前判断他未来一段时间内会不会变成坏客户。它和贷前审批不同贷前看的是“能不能借”贷中看的是“借了之后会不会变坏”。这个项目标题里的“python 基于机器学习的贷中风险预测模型”核心就是用 Python 把历史还款、交易、额度使用等行为数据喂给机器学习模型输出一个风险概率再配合源码和文档说明让你能跑通、能改、能讲清楚。适合谁做风控策略、数据挖掘、金融科技方向的学生和工程师尤其是需要一份能写进简历、能答辩、能复现的高分项目的人。热搜里常出现“机器学习模型”“python代码”“机器学习入门”但真正落地时难点不在模型多深而在数据怎么切、标签怎么定、时间窗口怎么对齐。2. 贷中风险预测的数据切分与标签定义别让未来数据漏进训练集2.1 观察期、表现期、宽限期怎么切贷中模型最怕时间穿越。你拿 2024 年 1 月到 6 月的数据训练用 7 月的数据测试这没问题。但如果你在构造特征时用了 7 月才产生的还款记录模型在训练时就已经“偷看”了未来。常见做法是定义三个窗口观察期用来算特征表现期用来定标签宽限期用来缓冲。比如观察期取放款后前 3 个月表现期取第 4 到第 6 个月宽限期 15 天。标签定义表现期内出现逾期超过 15 天标为 1否则为 0。这个切法在消费贷场景里比较稳因为大多数早期风险会在前 6 期暴露。import pandas as pd # 假设 loan_df 包含 loan_id, user_id, loan_date, due_date, repay_date, repay_amount # 先算每笔贷款的期数 loan_df[loan_date] pd.to_datetime(loan_df[loan_date]) loan_df[due_date] pd.to_datetime(loan_df[due_date]) loan_df[repay_date] pd.to_datetime(loan_df[repay_date]) # 观察期放款后 90 天内 obs_end loan_df[loan_date] pd.Timedelta(days90) # 表现期第 91 天到第 180 天 perf_start loan_df[loan_date] pd.Timedelta(days91) perf_end loan_df[loan_date] pd.Timedelta(days180) # 标签表现期内是否出现逾期超过 15 天 loan_df[overdue_days] (loan_df[repay_date] - loan_df[due_date]).dt.days loan_df[is_bad] ((loan_df[overdue_days] 15) (loan_df[due_date] perf_start) (loan_df[due_date] perf_end)).astype(int)逻辑说明先转日期类型再按放款日推算观察期和表现期边界。overdue_days是实际还款日减应还日大于 15 才算坏。参数上90 天和 180 天不是固定的如果产品期限短可以改成 30/90如果期限长可以拉长到 180/360。注意宽限期不要设太长否则坏样本会被稀释。2.2 特征工程从还款行为里挖出风险信号贷中特征一般分四类还款行为、额度使用、交易流水、多头借贷。还款行为包括历史逾期次数、最大逾期天数、平均还款间隔额度使用包括额度使用率、最近 30 天使用率变化交易流水包括月均消费金额、消费笔数多头借贷包括近 3 个月申请次数、已用额度占比。这些特征在 Python 里用 pandas 的 groupby 和 rolling 就能算。# 按用户聚合还款行为 repay_feat loan_df.groupby(user_id).agg( total_loans(loan_id, count), max_overdue(overdue_days, max), avg_overdue(overdue_days, mean), overdue_cnt(overdue_days, lambda x: (x 0).sum()) ).reset_index() # 额度使用率假设有 credit_df 包含 user_id, total_limit, used_limit credit_df[usage_rate] credit_df[used_limit] / credit_df[total_limit] credit_feat credit_df.groupby(user_id)[usage_rate].mean().reset_index() credit_feat.columns [user_id, avg_usage_rate] # 合并特征 model_df repay_feat.merge(credit_feat, onuser_id, howleft) model_df model_df.merge(loan_df[[user_id, is_bad]].drop_duplicates(), onuser_id)逻辑说明groupby按用户聚合agg里用 lambda 算逾期笔数。usage_rate是已用额度除以总额度反映资金紧张程度。合并时用 left join 保留所有用户。参数上max_overdue和avg_overdue对风险区分度最高通常排在特征重要性前五。注意不要用未来窗口的还款记录算特征否则 AUC 会虚高到 0.9 以上上线就翻车。3. 用 Python 跑通贷中风险预测模型从 LightGBM 训练到评分卡输出3.1 为什么选 LightGBM 而不是逻辑回归逻辑回归可解释性强但贷中行为特征非线性关系多比如额度使用率和风险不是简单线性。LightGBM 能自动处理缺失值、支持类别特征、训练速度快在中小规模数据上表现稳定。常见做法是先用 LightGBM 跑基线再用 SHAP 做解释。如果答辩需要可解释性可以同时训练逻辑回归做对比。参数上num_leaves设 31 到 63learning_rate设 0.05n_estimators设 500 到 1000min_child_samples设 20 到 50。这些值不是绝对的但在这个场景里比较稳。import lightgbm as lgb from sklearn.model_selection import train_test_split from sklearn.metrics import roc_auc_score # 特征列 features [total_loans, max_overdue, avg_overdue, overdue_cnt, avg_usage_rate] X model_df[features] y model_df[is_bad] # 按 7:3 切分 X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.3, random_state42, stratifyy) # 训练 LightGBM params { objective: binary, metric: auc, num_leaves: 31, learning_rate: 0.05, n_estimators: 500, min_child_samples: 30, subsample: 0.8, colsample_bytree: 0.8, random_state: 42 } model lgb.LGBMClassifier(**params) model.fit(X_train, y_train) # 评估 y_pred model.predict_proba(X_test)[:, 1] print(AUC:, roc_auc_score(y_test, y_pred))逻辑说明stratifyy保证训练集和测试集坏样本比例一致。subsample和colsample_bytree防过拟合。AUC 一般能到 0.75 到 0.85如果低于 0.7检查特征是否穿越或标签定义太宽。参数上num_leaves越大模型越复杂容易过拟合min_child_samples越大越保守。建议先用默认参数跑一遍再网格搜索。3.2 评分卡转换把概率变成可解释的分数模型输出的是概率业务方更习惯分数。常见做法是用score offset factor * ln(odds)其中odds p / (1 - p)。offset 和 factor 根据业务定比如基准分 600每 50 分 odds 翻倍。这样每个客户得到一个 300 到 850 的分数低于阈值就预警。import numpy as np def prob_to_score(prob, base_score600, base_odds50, pdo50): # pdo: 每增加 pdo 分odds 翻倍 factor pdo / np.log(2) offset base_score - factor * np.log(base_odds) odds prob / (1 - prob) score offset factor * np.log(odds) return np.round(score, 0) model_df[score] prob_to_score(y_pred) model_df[risk_level] pd.cut(model_df[score], bins[0, 500, 600, 700, 850], labels[高, 中, 低, 极低])逻辑说明base_score是基准分base_odds是基准 oddspdo是翻倍分数。np.log(odds)把概率转成线性分数。pd.cut按分数分档。参数上pdo越小分数越敏感一般设 20 到 50。注意概率为 0 或 1 时 log 会报错实际用的时候加个极小值。4. 贷中风险预测的避坑与排查血泪经验五条4.1 现象AUC 高得离谱上线就崩原因特征里混入了表现期数据比如用“未来 3 个月还款状态”算特征。解决严格按时间切分所有特征只来自观察期标签只来自表现期。用loan_date和due_date做硬隔离别偷懒。4.2 现象坏样本太少模型全预测为好客户原因贷中坏样本占比通常 1% 到 5%直接训练会偏向多数类。解决用scale_pos_weight或class_weightbalanced也可以对坏样本过采样。LightGBM 里设scale_pos_weight 负样本数 / 正样本数一般能提升召回。4.3 现象特征重要性里“用户 ID”排第一原因用户 ID 被当成数值特征模型记住了 ID 和标签的对应关系。解决训练前 drop 掉 ID 类字段或者转成类别特征但限制基数。常见做法是只保留行为聚合特征不保留原始 ID。4.4 现象评分卡分数分布挤在中间区分度差原因pdo设得太大或太小或者概率本身区分度不够。解决先看 AUC 和 KS如果 KS 低于 0.3先调模型如果 KS 正常但分数挤调整base_score和pdo让分数拉开。一般pdo50比较稳。4.5 现象答辩时被问“为什么用 LightGBM 不用 XGBoost”原因没准备选型对比。解决提前跑一个 XGBoost 基线对比 AUC、训练时间、内存占用。LightGBM 在样本量几万到几十万时训练更快内存更小但 XGBoost 在小样本上可能更稳。把对比表格放进答辩 PPT比空口说更有说服力。5. 把模型讲成答辩亮点源码、文档、PPT 的三点对齐技巧答辩 PPT 最怕三件事模型讲不清、代码说不明、业务落不了地。我的习惯是先把源码里的train.py和feature_engineer.py跑通确保输出 AUC 和 KS 能复现再把文档说明里的数据字典、特征列表、参数表整理成一页表格最后在 PPT 里用一页讲清楚“观察期-表现期-宽限期”的时间轴用一页放特征重要性 Top 10用一页放评分卡分档和业务建议。这样评委问什么都有对应材料。材料必须包含常见扣分点源码数据切分、特征工程、模型训练、评分转换没有随机种子结果不可复现文档说明数据字典、特征含义、参数说明、运行步骤只写“运行 main.py”没写依赖版本答辩 PPT时间轴、特征重要性、评分卡、业务建议堆公式不讲业务落地进阶技巧用 SHAP 值解释单个客户的评分。比如某个客户分数低SHAP 显示max_overdue贡献最大你就可以在答辩时说“这个客户历史最大逾期 30 天所以分数被拉低”。这比只讲 AUC 更有说服力。验证方法也简单从测试集里抽 10 个坏客户和 10 个好客户分别看 SHAP 图确认模型学到的逻辑和业务常识一致。如果发现模型靠“用户 ID”或“放款金额”区分说明特征有问题得回去改。我踩过最大的坑是为了追求高 AUC把表现期数据混进特征结果答辩时被问“这个特征放款时能拿到吗”当场卡住。后来养成习惯每加一个特征就问自己“这个字段在观察期结束那天能拿到吗”拿不到就删。希望帮到你。本文还有配套的精品资源点击获取
返回列表