尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

银行信用卡风控四模型实战:从申请人到欺诈的Python代码落地

发布时间:2026/9/26 7:35:04

资讯中心
01
ARTICLE

银行信用卡风控四模型实战:从申请人到欺诈的Python代码落地

银行信用卡风控四模型实战:从申请人到欺诈的Python代码落地
简介这份资源面向模式识别课程学习者和金融风控入门者围绕银行信用卡场景完整落地四类评级模型申请人评级、行为评级、收款催收评级与欺诈评级帮助读者理解从信用违约预测到催收策略、欺诈识别的全流程建模思路。压缩包共18个文件约7.67MB包含8个csv数据文件、4个Python源码、4个pkl模型文件以及字体与说明文档覆盖数据、代码与训练产物便于直接复现与二次修改。项目按数据预处理与分析、模型构建、模型评估与优化三阶段推进涉及缺失值、重复值、异常值处理、特征选择与可视化并采用降维和随机森林等机器学习算法通过交叉验证测试准确度与稳定性。已有130人学习适合作为课程设计、实验报告或风控建模练手参考能帮助读者掌握评级模型的设计逻辑、评估方法与改进方向。1. 从一份银行风控课设说起四个评级模型到底在评什么信用卡风控不是单点判断而是一条从申请到催收的完整链路。这份模式识别课程设计把链路拆成了四个模型申请人评级、行为评级、收款评级催收评级、欺诈评级。每个模型解决一个独立问题但共享同一套数据预处理和评估框架。申请人评级看的是“这个人还没拿到卡该不该批”行为评级看的是“已经持卡的人未来会不会逾期”收款评级看的是“已经逾期的人该用什么力度催”欺诈评级看的是“这笔申请是不是假的”。四个模型串起来覆盖了信用卡生命周期的主要风险节点。资源包里是 Python 源码加文档说明目录结构清晰Fraud_rating.py、applicant_rating.py、Collection_rating.py、Behavior_rating.py四个脚本对应四个模型model目录放训练产物file_processed放预处理后的数据file_list是原始文件清单SimHei.ttf用来解决 matplotlib 中文显示问题。技术栈是 MindSpore 加 scikit-learn 混合随机森林是主力算法降维处理用在特征选择阶段。适合正在做模式识别课程设计的学生也适合想了解银行风控建模全流程的 Python 开发者。下面按“数据怎么洗 → 模型怎么搭 → 坑怎么避 → 怎么验证”的顺序拆一遍。2. 数据预处理与特征工程从原始字段到模型可吃的矩阵2.1 缺失值、重复值与异常值的处理顺序拿到银行信用卡数据第一件事不是急着往模型里灌而是把数据洗干净。这份课设的预处理流程写在文档说明里顺序是理解数据 → 缺失值处理 → 重复值处理 → 异常值检测与处理 → 特征选择 → 数据可视化。顺序不能乱因为缺失值填充会改变分布如果先做异常值检测填充后的值可能被误判为异常。缺失值处理分两类数值型字段用中位数填充类别型字段用众数填充。中位数比均值抗异常值众数在类别不平衡时更稳。重复值直接去重但要注意银行数据里同一个人可能有多条申请记录去重前得确认业务主键是什么。异常值检测用 IQR 方法超出 Q1-1.5IQR 和 Q31.5IQR 范围的值标记为异常但不要直接删先看业务含义——有些“异常”其实是高净值客户的大额交易。import pandas as pd import numpy as np # 读取原始数据 df pd.read_csv(file_list/credit_data.csv) # 缺失值数值型用中位数类别型用众数 num_cols df.select_dtypes(include[np.number]).columns cat_cols df.select_dtypes(include[object]).columns for col in num_cols: df[col].fillna(df[col].median(), inplaceTrue) for col in cat_cols: df[col].fillna(df[col].mode()[0], inplaceTrue) # 重复值按业务主键去重 df.drop_duplicates(subset[applicant_id], keepfirst, inplaceTrue) # 异常值IQR 标记不直接删 for col in num_cols: Q1 df[col].quantile(0.25) Q3 df[col].quantile(0.75) IQR Q3 - Q1 lower Q1 - 1.5 * IQR upper Q3 1.5 * IQR df[f{col}_outlier] ((df[col] lower) | (df[col] upper)).astype(int)这段代码的逻辑是先填充缺失值保证数据完整再去重保证样本独立最后用 IQR 标记异常值而不是删除。参数上keepfirst保留第一条记录适合申请场景如果是行为数据可能要保留最新一条。1.5是 IQR 的经典系数调到 3 会放宽异常判定适合长尾分布明显的字段。2.2 特征选择与降维为什么随机森林之前要先做这一步原始字段可能有几十上百个直接扔进随机森林不是不行但训练慢、解释性差、容易过拟合。课设里用了降维处理常见做法是先用方差过滤去掉低方差特征再用皮尔逊相关系数剔除高度共线的字段最后用随机森林的 feature_importances_ 做一轮筛选。from sklearn.feature_selection import VarianceThreshold from sklearn.ensemble import RandomForestClassifier # 方差过滤去掉取值变化极小的特征 selector VarianceThreshold(threshold0.01) X_selected selector.fit_transform(X) # 随机森林特征重要性 rf RandomForestClassifier(n_estimators100, random_state42) rf.fit(X_selected, y) importances pd.Series(rf.feature_importances_, indexselector.get_feature_names_out()) top_features importances.nlargest(20).index.tolist()threshold0.01是经验值低于这个方差的特征对模型几乎没贡献。n_estimators100是随机森林的常用起点树太少不稳定树太多训练慢100 到 300 之间比较平衡。top_features取前 20 个具体数量看业务能接受多少字段——申请人评级通常 15 到 25 个特征就够欺诈评级可能需要更多。注意降维不是必须的如果数据量小、特征少直接上随机森林也能跑。课设里做降维是为了讲清楚流程实际项目中要看数据规模和业务解释成本。3. 四个评级模型的构建从申请人到欺诈的代码落地3.1 申请人评级模型二分类与阈值调整申请人评级本质是二分类违约或不违约。课设用随机森林做基模型输出概率后按阈值切分。默认阈值 0.5 在风控场景往往不合适因为违约样本少模型倾向于预测“不违约”。常见做法是调低阈值提高召回率宁可错杀不可放过。from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report, roc_auc_score # 假设 X 是特征矩阵y 是标签1违约0正常 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy ) rf_applicant RandomForestClassifier( n_estimators200, max_depth10, min_samples_leaf5, class_weightbalanced, random_state42 ) rf_applicant.fit(X_train, y_train) # 预测概率并调整阈值 y_prob rf_applicant.predict_proba(X_test)[:, 1] threshold 0.35 # 低于默认 0.5提高违约召回 y_pred (y_prob threshold).astype(int) print(classification_report(y_test, y_pred)) print(AUC:, roc_auc_score(y_test, y_prob))class_weightbalanced让模型自动调整类别权重缓解样本不平衡。max_depth10控制树深防止过拟合。min_samples_leaf5保证叶子节点至少 5 个样本避免模型记住噪声。阈值 0.35 是示例实际要用验证集画 KS 曲线或 PR 曲线来定。AUC 是评估排序能力的核心指标风控里通常要求 0.75 以上。3.2 行为评级模型时间窗口与滑动特征行为评级看的是历史还款记录、逾期次数、额度使用率等。和申请人评级最大的区别是行为数据有时间维度不能简单把每个月的记录当独立样本。课设里的做法是构造滑动窗口特征比如“过去 3 个月平均逾期天数”“过去 6 个月最大逾期次数”。# 假设原始行为表有 customer_id, month, overdue_days, credit_usage behavior pd.read_csv(file_processed/behavior_data.csv) # 按客户分组构造滑动窗口特征 behavior[overdue_3m_avg] behavior.groupby(customer_id)[overdue_days].transform( lambda x: x.rolling(3, min_periods1).mean() ) behavior[overdue_6m_max] behavior.groupby(customer_id)[overdue_days].transform( lambda x: x.rolling(6, min_periods1).max() ) behavior[usage_3m_std] behavior.groupby(customer_id)[credit_usage].transform( lambda x: x.rolling(3, min_periods1).std() ) # 取每个客户最后一条记录作为当前状态 latest behavior.sort_values(month).groupby(customer_id).tail(1)rolling(3)表示 3 个月窗口min_periods1保证第一个月也有值。transform保持原表行数不变方便后续合并。取最后一条记录是因为行为评级预测的是“未来会不会逾期”用最新状态最合理。如果直接用所有月份的数据训练会引入时间泄漏——用未来的信息预测过去。3.3 收款评级模型多分类与催收策略映射收款评级催收评级的输出不是简单的“违约/不违约”而是“该用什么力度催”。课设里把它设计成多分类轻度催收、中度催收、重度催收。标签来自历史催收记录中的实际措施和回收率。from sklearn.ensemble import RandomForestClassifier from sklearn.preprocessing import LabelEncoder # 标签编码轻度0中度1重度2 le LabelEncoder() y_collection le.fit_transform(collection_labels) rf_collection RandomForestClassifier( n_estimators150, max_depth8, min_samples_leaf10, random_state42 ) rf_collection.fit(X_collection_train, y_collection_train) # 预测并映射回策略 y_pred_collection rf_collection.predict(X_collection_test) strategy_map {0: 短信提醒, 1: 电话催收, 2: 上门催收} predicted_strategies [strategy_map[i] for i in y_pred_collection]max_depth8比申请人模型更浅因为催收策略的决策边界不宜太复杂否则业务方没法解释。min_samples_leaf10保证每个策略至少覆盖足够样本。多分类的评估不能用 AUC要用混淆矩阵和 macro-F1。实际落地时还要考虑催收成本——重度催收成本高模型不能把所有客户都推到重度。3.4 欺诈评级模型不平衡样本与代价敏感欺诈样本通常极少可能只占 1% 到 5%。直接用随机森林会偏向多数类。课设里的处理方式是组合采样加代价敏感学习。常见做法是 SMOTE 过采样少数类同时设置 class_weight 为 balanced_subsample。from imblearn.over_sampling import SMOTE from sklearn.ensemble import RandomForestClassifier # SMOTE 过采样 smote SMOTE(random_state42) X_fraud_res, y_fraud_res smote.fit_resample(X_fraud_train, y_fraud_train) rf_fraud RandomForestClassifier( n_estimators300, max_depth12, min_samples_leaf3, class_weightbalanced_subsample, random_state42 ) rf_fraud.fit(X_fraud_res, y_fraud_res) # 欺诈场景更关注召回率 y_fraud_prob rf_fraud.predict_proba(X_fraud_test)[:, 1] y_fraud_pred (y_fraud_prob 0.3).astype(int)SMOTE在少数类样本之间插值生成新样本缓解不平衡。balanced_subsample是在每棵树训练时动态调整权重比全局 balanced 更细。阈值降到 0.3 是为了提高欺诈召回——漏掉一个欺诈客户的损失远大于误判一个正常客户。但阈值不能无限低否则误报太多人工审核扛不住。提示SMOTE 要在训练集上做测试集保持原始分布。如果在全量数据上过采样再划分测试集会被污染评估结果虚高。4. 模型评估与调参交叉验证、KS 与稳定性检查4.1 交叉验证与分层采样课设里用了交叉验证评估模型稳定性。风控数据类别不平衡必须用 StratifiedKFold 保证每折的类别比例一致。from sklearn.model_selection import StratifiedKFold, cross_val_score skf StratifiedKFold(n_splits5, shuffleTrue, random_state42) scores cross_val_score(rf_applicant, X, y, cvskf, scoringroc_auc) print(AUC 均值:, scores.mean(), 标准差:, scores.std())n_splits5是常用折数数据量小可以调到 10。shuffleTrue打乱顺序避免数据按时间排序导致的偏差。scoringroc_auc关注排序能力比准确率更适合不平衡场景。标准差大于 0.05 说明模型不稳定要检查特征或增加数据。4.2 KS 值与风控专用指标AUC 是通用指标风控里更常用 KSKolmogorov-Smirnov。KS 衡量的是好客户和坏客户累计分布的最大差值值越大区分能力越强。一般 KS 大于 0.3 算可用大于 0.4 算不错。from scipy.stats import ks_2samp def calculate_ks(y_true, y_prob): good y_prob[y_true 0] bad y_prob[y_true 1] ks_stat, _ ks_2samp(good, bad) return ks_stat ks calculate_ks(y_test, y_prob) print(KS:, ks)ks_2samp直接算两组分布的 KS 统计量。好客户和坏客户的概率分布差距越大KS 越高。如果 KS 低于 0.2模型基本不可用要回头检查特征工程。4.3 模型对比与选型依据课设里四个模型都用了随机森林但实际项目中可以对比逻辑回归、XGBoost、LightGBM。随机森林的优势是解释性好、不容易过拟合、对缺失值不敏感劣势是训练慢、对高维稀疏数据表现一般。逻辑回归可解释性最强但拟合非线性关系能力弱。XGBoost 和 LightGBM 在结构化数据上通常表现最好但调参复杂。模型优点缺点适用场景逻辑回归可解释性强、训练快非线性拟合弱申请人评级基线随机森林稳定、抗过拟合训练慢、解释性中等行为评级、欺诈评级XGBoost精度高、支持自定义损失调参复杂竞赛、高精度要求LightGBM速度快、内存占用低小数据容易过拟合大规模行为数据选型没有绝对答案要看数据规模、业务解释要求和团队技术栈。课设选随机森林是因为它平衡了效果和可解释性适合教学场景。5. 避坑与排查四个模型跑通前最容易翻车的地方5.1 中文显示乱码SimHei.ttf 没生效现象matplotlib 画图时中文变成方框。原因系统没有 SimHei 字体或者代码里没指定字体路径。解决把SimHei.ttf放到项目目录在绘图前设置plt.rcParams[font.sans-serif] [SimHei]并加上plt.rcParams[axes.unicode_minus] False解决负号显示问题。如果还不行用font_manager.FontProperties(fnameSimHei.ttf)显式加载。5.2 数据泄漏用未来信息预测过去现象模型在测试集上 AUC 0.95上线后效果暴跌。原因特征里包含了标签之后的信息比如用“最终还款状态”预测“是否逾期”。解决构造特征时严格按时间切分训练集用 T 时刻之前的数据测试集用 T 之后的数据。滑动窗口特征只允许用当前及之前月份的数据。5.3 类别不平衡准确率虚高但召回率极低现象欺诈模型准确率 99%但一个欺诈客户都没抓到。原因欺诈样本只占 1%模型全预测“正常”也能到 99% 准确率。解决不要看准确率看召回率、F1 和 AUC。用 SMOTE 过采样或 class_weight 调整权重。阈值从 0.5 降到 0.3 甚至 0.2根据业务能承受的误报率来定。5.4 特征共线性随机森林也会受影响现象两个高度相关的特征同时入模特征重要性被稀释模型解释性变差。原因随机森林虽然对共线性不如线性模型敏感但共线性特征会分摊重要性导致业务方看不懂。解决计算皮尔逊相关系数矩阵相关系数大于 0.8 的特征只保留一个。或者用 VIF方差膨胀因子筛选VIF 大于 10 的剔除。5.5 模型保存与加载路径和版本不一致现象训练好的模型保存后换台机器加载报错。原因Python 版本、库版本不一致或者保存路径用了绝对路径。解决用joblib.dump保存模型加载时确保 scikit-learn 版本一致。路径用相对路径或者把模型文件和代码放在同一目录。课设里model目录就是干这个的但要注意.pkl文件不要跨大版本使用。6. 从课设到落地四个模型串成评分卡流水线的技巧把四个模型单独跑通只是第一步真正有价值的是把它们串成一条流水线。我的习惯是写一个统一的pipeline.py按“申请 → 行为 → 催收 → 欺诈”的顺序调用每个模型输出一个分数最后加权汇总成客户风险总分。权重不是拍脑袋定的用逻辑回归在验证集上拟合四个分数到最终违约标签得到的系数就是权重。import joblib import numpy as np # 加载四个模型 rf_applicant joblib.load(model/applicant_rf.pkl) rf_behavior joblib.load(model/behavior_rf.pkl) rf_collection joblib.load(model/collection_rf.pkl) rf_fraud joblib.load(model/fraud_rf.pkl) def risk_pipeline(customer_data): # 四个模型分别输出概率 score_applicant rf_applicant.predict_proba(customer_data[applicant])[:, 1] score_behavior rf_behavior.predict_proba(customer_data[behavior])[:, 1] score_collection rf_collection.predict_proba(customer_data[collection])[:, 1] score_fraud rf_fraud.predict_proba(customer_data[fraud])[:, 1] # 加权汇总权重来自逻辑回归拟合 weights np.array([0.35, 0.25, 0.20, 0.20]) scores np.vstack([score_applicant, score_behavior, score_collection, score_fraud]).T final_score scores weights return final_score权重[0.35, 0.25, 0.20, 0.20]是示例实际要用验证集拟合。申请人评级权重最高因为申请环节是风险第一道闸门。欺诈评级权重不低因为欺诈损失通常大于违约损失。这个流水线的好处是每个模型可以独立迭代换掉一个不影响其他。验证方法上我一般会做三件事第一用时间外样本测试比如用 2023 年数据训练2024 年数据测试第二画 KS 和 Lift 曲线看模型在不同分数段的区分能力第三做压力测试把某个特征人为调高或调低看分数变化是否符合业务直觉。压力测试最容易发现“模型学了伪相关”的问题。还有一个技巧把四个模型的输出分数做分箱比如等频分 10 箱然后看每箱的实际违约率是否单调。如果单调性不好说明模型排序能力有问题要回头调特征或换算法。这个检查比 AUC 更直观业务方也更容易理解。从那以后我每次做完风控模型都强制走一遍时间外验证和压力测试不再只看交叉验证的 AUC。课设里的代码是起点真正落地还要补很多工程细节。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。