
简介面向银行信贷风控、数据科学及网页开发学习者这份Python银行信贷风险评估项目源码包覆盖从用户基本信息、借贷行为到征信数据的建模与部署流程解决违约概率预测和风险预警问题。压缩包共26个文件包含13个HTML页面、4个Python脚本、1份信贷数据集、1个模型文件及依赖配置整体仅856KB源码模块覆盖批量导入、风险评分、模型训练、数据分析和预警看板便于直接运行与二次开发。目前已有87人学习下载。资源以XGBoost算法为核心展现数据探索式分析、模型训练调参及AUC达0.72的性能评估并用Flask和Bootstrap搭建可视化风控预警平台。读者可获得完整源码、前端页面和模型文件适合课程设计、论文复现或金融风控项目参考也是掌握机器学习与Web应用结合的实用范例。 最近好几个做信贷风控的朋友都来问我同一个问题用Python能不能独立搭一套能跑的信贷风险评估项目我的回答很明确能而且这已经不是大银行才有的能力。你只需要一份结构清晰的历史借贷样本、一台带Python环境的电脑再加上一套标准建模流程就能做出一个可解释、可评估、可部署的风险评估模型。这次分享的Python银行信贷风险评估源码做的就是这件事从数据清洗开始经过特征工程、模型训练、效果评估最终输出借款人违约概率和风险等级。理论层面的东西也许不适合直接当生产系统用但对想入门风控数据分析的人、金融科技从业者以及对信贷业务有完整技术落地需求的团队这套项目源码就是最直接的参照物。我尽量把每个环节的为什么也讲清楚少走弯路。1. 为什么银行风控项目会首选Python1.1 从评分卡到Python生态的迁移银行信贷这个圈子里过去做风控模型最常用的工具是SAS和Excel少数机构用SPSS。这些工具的优势在于成熟、可控、监管认可度高缺点也很明显收费贵、迭代慢、数据处理能力有限。你想在Excel里处理几百万条借贷明细光是打开文件就能把人逼疯。Python出现的意义不是把旧工具全部推翻而是把数据探查、特征加工、模型训练、效果评估和线上部署全部收拢到同一条流水线上。pandas做数据清洗scikit-learn做基础建模LightGBM或XGBoost做更复杂的非线性模型SHAP解释变量贡献Flask或FastAPI把模型包装成接口。每一步都有现成的库配合Jupyter Notebook风控人员在一天之内就能完成过去需要一周的迭代试验。1.2 项目要解决的真实信贷场景这个项目源码瞄准的不只是实验而是几个真实信贷机构都会遇到的场景。第一是申请评分用户提交贷款申请时根据身份信息、收入水平、负债率、历史逾期等维度判断这笔申请该不该批。第二是额度和定价模型输出的违约概率可以映射成额度倍数和利率档位风险越高额度越小利率越高。第三是存量客户管理对已放款客户做贷后预警一旦风险信号上升提前触发催收或降额策略。这套源码按申请评分场景来设计但核心流程换一批字段后同样可以迁移到反欺诈、行为评分等方向。1.3 适合谁来学能学到什么我给不同朋友的定位不太一样。对刚入行的数据分析师这份源码是理解“建模落地”的完整样例对金融科技公司的研发同学它是从模型训练到API封装可直接参考的工程模板对银行里还在用SQL做风险策略的同事它展示的是Python在自动化风控流程中的真实能力。当然它不会替代评分卡在监管报送里的法规定位但作为辅助决策和策略预研价值已经足够明显。可以说学会这一套你就算真正迈进了Python风控建模的大门。2. 信贷数据长什么样先搞清这三个字段2.1 数据集字段和业务含义信贷风险评估项目的第一步不是找模型而是先弄清楚手里的数据长什么样。大多数信贷数据集可以分成几块借款人基本信息、申请贷款信息、信用历史信息、还款表现信息。我在源码里用的是脱敏后的模拟数据字段设计参照了常见信贷数据集的风格。你完全可以按这个结构替换成自己的数据。下面这张表是核心字段的示意先看这三个就够了字段类别字段名业务含义数据样例借款信息loan_amount申请贷款金额50000还款能力annual_income借款人年收入150000信用历史overdue_count近两年逾期次数2你可能觉得字段太少但实际建模初期先把直观变量用熟练比急着堆几百个特征更有效。尤其对新人来说理解一个字段为什么能预测违约比多跑一遍算法重要得多。比如逾期次数这个字段业务逻辑非常直接过去经常晚还钱的人未来大概率也会晚还。年龄和收入则更多反映还款能力和稳定性。2.2 目标变量怎么定信贷模型的目标变量不是随便找一个列就能用。一般会把“违约”定义成在观察期内是否出现过指定天数的逾期。比如观察期定为贷款发放后12个月如果发生90天以上的逾期则标记为1否则为0。这个定义直接影响模型学习的信号如果定义过宽噪声很大定义过窄坏样本太少模型学不到东西。在源码里我直接把目标列命名为is_default代码中可以这样读取import pandas as pd df pd.read_csv(data/credit_data.csv) print(df[is_default].value_counts(normalizeTrue))这里要特别注意is_default的分布通常是不均衡的坏样本占比可能只有5%到10%这就是后面所有评估环节必须小心处理的起点。2.3 样本划分的纪律信贷数据不能简单随机切分因为业务和宏观环境在变化。比较稳妥的做法是用时间靠前的样本做训练和验证用时间靠后的样本做测试。这样能模拟真实的线上场景模型在历史数据上学习再应用到未来客户。源码中预留了loan_date字段切分时按它排序后再做训练集、验证集、测试集的划分。3. 特征工程里最容易被忽略的致命细节3.1 数据泄漏最常见也最隐蔽的坑特征工程里能踩的坑很多但最应该警惕的是数据泄漏。简单说就是你把“未来结果”当成了“历史特征”。一个很典型的例子如果你的训练表里包含一列“当前是否已还款”然后拿它去预测是否违约模型会得到一个接近1的AUC因为“是否已还款”已经是结果了。上线之后这一列根本拿不到模型直接失效。更隐蔽的泄漏是时间窗口错位。比如你想用“最近一个月的消费金额”作为特征但你的特征表统计的是贷款发放之后一个月的数据这同样是在用未来信息。项目源码里我刻意做了数据清洗保证所有特征都来自申请时点或更早的历史这一点在你自己造数据时一定要反复检查。3.2 缺失值不是小事更不能随便填0收入字段的缺失率如果达到20%你用均值填充还是在0填充对模型影响极大。我见过不少项目简单填0后模型训练得很开心但上线后对收入缺失的客户预测极不稳定。更好的做法是给缺失单独一个分支先判断缺失本身是否与风险相关再决定是补充数值还是构造缺失指示变量。源码里的preprocess.py提供了一种比较稳妥的方案def fill_income(df): df[income_missing] df[annual_income].isna().astype(int) df[annual_income] df[annual_income].fillna(df[annual_income].median()) return df这个处理同时保留了“缺失”这个信号本身也解决了模型无法接受空值的问题。3.3 样本不平衡先切分再过采样信贷数据天然不平衡这时候如果你直接用原始数据训练模型会倾向于把所有样本都预测为“好客户”因为这样已经能保证90%以上的准确率。解决办法是过采样或者给少数类加权重。这里必须强调一个原则先划分训练集和测试集再在训练集内部做SMOTE过采样千万不要在全量数据上做过采样再切分否则会造成严重的样本交叉泄漏测试集的评估结果会虚高。下面这段代码是正确顺序from sklearn.model_selection import train_test_split from imblearn.over_sampling import SMOTENC train, test train_test_split(df, test_size0.2, stratifydf[is_default]) smote SMOTENC(categorical_features[loan_purpose], random_state42) X_res, y_res smote.fit_resample(train.drop(is_default, axis1), train[is_default])4. 三类模型怎么选逻辑回归、随机森林与LightGBM4.1 为什么先跑逻辑回归逻辑回归在信贷风控里地位非常高因为它自带可解释性训练速度快输出是概率形式方便设定阈值。监管审计时你也能讲清楚每个变量的系数方向。作为基线模型我会先用逻辑回归跑一版看AUC和KS做到什么水平再决定是否引入更复杂的模型。4.2 为什么最终推荐LightGBM随机森林在中小数据集上表现稳定但速度慢模型文件大。LightGBM是梯度提升树的代表对缺失值容忍度高能直接处理类别特征训练速度远快于XGBoost和随机森林所以在工业风控项目里非常受欢迎。对比一下你就明白维度逻辑回归随机森林LightGBM可解释性高中低非线性能力低高高训练速度快中快对缺失值容忍度低中高是否适合信贷建议基线必备可用主力推荐4.3 核心训练代码源码里train.py是核心训练入口大致逻辑如下import lightgbm as lgb from sklearn.model_selection import StratifiedKFold params { objective: binary, boosting_type: gbdt, learning_rate: 0.05, num_leaves: 31, n_estimators: 300, reg_alpha: 0.5, reg_lambda: 1.0, } cv StratifiedKFold(n_splits5, shuffleTrue, random_state42) for fold, (tr_idx, va_idx) in enumerate(cv.split(X, y)): train_set lgb.Dataset(X.iloc[tr_idx], y.iloc[tr_idx]) valid_set lgb.Dataset(X.iloc[va_idx], y.iloc[va_idx]) model lgb.train(params, train_set, valid_sets[valid_set], callbacks[lgb.early_stopping(50)])超参数里我建议重点关注learning_rate和num_leaves。learning_rate设太大会过拟合设太小训练时间拉长num_leaves控制树的复杂度一般从31开始在验证集上观察AUC变化再调整。4.4 模型输出的业务含义LightGBM输出的是违约概率不是是否违约。这个概率最后会映射成风险评分常见做法是Score 600 (log(odds)) * 20这种形式也可以直接使用概率分档比如小于0.03为A级0.03到0.08为B级其他为C级。源码里提供了score_level映射函数方便直接导入业务系统。5. 评估信贷模型准确率真的没什么用5.1 不平衡数据下的评估陷阱如果坏样本只占5%你把所有客户都预测成“好”准确率也有95%但这个模型没有任何风险区分能力。所以信贷模型评估基本不看准确率而是看这几个指标。混淆矩阵看模型在坏样本和好样本上的分类表现。ROC-AUC衡量排序能力越大越好0.7以上算可用。KS值好客户和坏客户累计概率分布的最大差距0.3以上在风控里算不错。Lift值模型选出的高坏账率群体比例看业务提升量。5.2 评估代码直接跑evaluate.py里封装了完整的指标计算from sklearn.metrics import roc_auc_score, roc_curve, confusion_matrix y_prob model.predict(X_test) auc roc_auc_score(y_test, y_prob) fpr, tpr, _ roc_curve(y_test, y_prob) ks max(tpr - fpr) cm confusion_matrix(y_test, (y_prob 0.5).astype(int)) print(fAUC: {auc:.4f}, KS: {ks:.4f}) print(Confusion Matrix:, cm)5.3 阈值决定业务结果模型给的是概率最终放不放款由阈值决定。阈值越低通过率越高坏账也越高阈值越高审核越严可能错失好客户。实际业务里我们会输出不同阈值下的通过率和坏账率表格再由策略人员决定用哪个阈值。这一步非常关键因为同一个模型在不同产品线里可能有完全不同的最优阈值。以测试集为例假设模型预测结果分布如下概率阈值通过率坏账率0.160%8.2%0.345%4.5%0.532%2.6%你可以看到阈值从0.1调到0.5通过率从60%降到32%坏账率也从8.2%降到2.6%。这就是模型和策略的衔接点不要在模型阶段就替业务决定了放不放。6. 项目源码核心模块拆解与运行说明6.1 项目目录和文件职责项目源码的结构我按工程化方式组织不是单个notebook这样看起来更规范也方便后续扩展credit_risk/ ├─ data/ │ └─ credit_data.csv ├─ src/ │ ├─ preprocess.py │ ├─ train.py │ ├─ evaluate.py │ └─ predict.py ├─ requirements.txt └─ README.mdpreprocess.py数据读取、缺失值处理、特征工程、训练集切分。train.py逻辑回归和LightGBM训练模型保存到models/目录。evaluate.py输出AUC、KS、混淆矩阵、坏账率表。predict.py加载模型对单条或多条样本做预测。requirements.txt固定依赖版本。6.2 环境准备和依赖安装安装环节是很多新手卡住的第一步。建议先用虚拟环境避免包版本互相冲突并且在requirements.txt里锁好版本。核心依赖如下pandas2.0.3 numpy1.24.3 scikit-learn1.3.0 imbalanced-learn0.11.0 lightgbm4.1.0 shap0.44.0 flask2.3.2安装命令只一条pip install -r requirements.txt如果你还没有独立的Python环境可以用python -m venv venv来创建然后执行激活命令。这一步和“python环境变量怎么配”是同一类基础操作别嫌麻烦环境干净能帮你省掉很多莫名其妙的报错。6.3 运行和部署最小示例训练完模型后部署到接口是最常见的落地方式。我在predict.py里放了一个最小可用的Flask服务示例from flask import Flask, request, jsonify import joblib import pandas as pd app Flask(__name__) model joblib.load(models/lightgbm.pkl) app.route(/predict, methods[POST]) def predict(): data request.get_json(forceTrue) df pd.DataFrame([data]) prob model.predict(df)[0] return jsonify({default_probability: round(float(prob), 4)}) if __name__ __main__: app.run(host0.0.0.0, port8000)这样一条/predict接口就能接收新样本特征返回违约概率。代码量不大但已经足够演示风控模型如何上线服务。7. 从开发到上线的实战避坑经验7.1 我在特征泄漏上吃过亏我最早做这个项目的时候数据表里有一列叫repay_status当时觉得字段很全接进去之后AUC直接0.98心里还挺美。后来一查这个字段记录的是“贷款发放后的还款状态”等于我把结果塞进特征里了。把特征时序对齐后AUC回落到0.73。所以我现在给团队定的规矩是每张特征表必须写明时间窗口建模前先审计特征生成逻辑任何“未来才有的字段”一律不能进模型。7.2 过采样顺序和随机种子刚才说过先切分再过采样。但在代码层面还有一个容易忽略的细节SMOTENC在构建时会引入随机噪声所以必须设random_state否则每次跑出来的结果都有波动很难对比实验。同理五折交叉验证里的shuffle也要固定随机种子。7.3 线上监控比模型本身更难模型上线不代表工作结束反而是监控的开始。我建议至少监控两个东西一是特征分布漂移用PSIPopulation Stability Index衡量超过0.1就要关注超过0.25一般需要重训或回滚二是线上实际坏账率与测试集坏账率是否有显著偏差。很多团队把模型一部署就当甩手掌柜结果半年后才发现效果已经衰减到完全不可用。这一块在面试里很少会考但实际业务里特别容易被问住。7.4 一份可以写进简历的完整项目如果你打算把这个项目放进简历我会建议你把“特征泄漏踩坑和修复过程”写进项目描述。面试官最忌讳听到“数据丢进去模型出来了”这种答案反而很认可能讲清楚坑、原因和规避方案的候选人。我自己带新人时最看重的也是这种对风险边界的敏感度。顺便说一句如果你在实际复现时遇到LightGBM版本和pandas不兼容的报错优先去看requirements.txt里的版本多数问题都是版本漂移导致的。本文还有配套的精品资源点击获取