尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
信贷风控实战:从数据清洗到风险定价的完整建模流程
简介2020年全国大学生数学建模竞赛C题“中小微企业信贷决策”实践资料包包含可编辑Word论文与MATLAB源代码面向参赛学生、毕业设计者及金融数据分析学习者系统展示基于统计建模解决企业信贷风险评估的完整流程。压缩包共160个文件总大小约248.35MB涵盖xlsx企业数据表、txt说明文件、m源码、csv数据集、docx文档及jpg/png图表文件类型覆盖原始数据、特征处理结果、模型代码与可视化输出便于按需查阅。已有663人学习下载。论文部分围绕信息不对称、风险高、信用评估难等小微信贷特点详述数据预处理缺失值/异常值处理、清洗、特征工程以及线性回归、决策树等模型的构建与交叉验证MATLAB代码则对应实现数据导入、建模、训练、测试等模块读者可对照论文复现并结合各类图表直观理解模型预测效果与实际数据的差异。整体上这套资料将理论与实战结合是理解数学建模在金融风控中落地应用的高价值案例。1. 把中小微企业信贷决策C题拆成四份数据、评分、定价、检验拿到这份2020年数学建模竞赛C题资源包时第一反应不是「这是一份论文」而是一整套可以落地复现的中小微企业信贷决策流程。赛题给了一百多家企业的进销项发票、纳税申报和历史信贷记录要回答三个问题哪些企业该放贷、额度给多少、利率怎么定。看得多了会发现这道题表面是数据分析内核其实是银行信贷审批里的风险定价。这份资源适合两类人一类是准备参赛拿高分的学生另一类是想用真实赛题练手信贷风控建模的从业者。我习惯把这类题拆成四步解洗干净数据画像、给企业打信用分、把分数折算成额度和利率、最后做稳健性检验。下面按这个顺序把每个环节的参数选择和踩坑点讲透。2. 数据清洗与特征工程从进销项发票到企业信贷画像2.1 先想清楚企业拿什么还钱再动手写 groupby信贷决策的风险来源拆开只有两件事企业还不起钱是能力问题不想还钱是意愿问题。能力看经营流水意愿看历史违约记录。所以特征工程的每一列都得服务于这两件事之一。我一般先算三个方向的特征经营规模比如销项金额、进项金额、税额经营稳定性比如连续活跃月份数、收入波动幅度还有申报与发票的偏离度用纳税申报收入比上发票销项收入偏离越大越可疑。这三个方向不是拍脑袋定的它们分别对应风险敞口和违约概率这两个核心变量。如果连经营规模都算不准后面的评分模型再精细也是空中楼阁。C题的数据通常把发票明细和企业信息分成多个表第一步一定是做聚合而不是直接建模。很多队伍急着上模型结果特征表里全是缺失值回头补数据的成本远高于一次仔细的清洗。2.2 主线代码一版够用的企业信用画像构建下面这版代码是这类赛题里最常见的骨架字段名换成自己的数据后就能跑通。import pandas as pd import numpy as np def build_credit_profile(invoice, sales_report): # 字段假设ent_id 企业IDdirection 进项/销项amount 金额tax 税额date 开票日期 df invoice.copy() df[month] pd.to_datetime(df[date]).dt.to_period(M) # 按企业、方向、月份三层聚合 agg df.groupby([ent_id, direction, month]).agg( amount_sum(amount, sum), invoice_cnt(amount, count), tax_sum(tax, sum), ).reset_index() # 销项收入按月转成宽表后续特征都基于它 out agg[agg[direction] out].pivot_table( indexent_id, columnsmonth, valuesamount_sum, aggfuncsum ) # 只取最近6个月避免用未来的数据倒退特征 recent out.iloc[:, -6:] profile pd.DataFrame(indexout.index) profile[active_months] recent.notna().sum(axis1) profile[sales_ma3] out.ffill(axis1).rolling(3, axis1).mean(axis1).iloc[:, -1] profile[sales_std] recent.std(axis1).fillna(0) profile[sales_total] recent.sum(axis1).fillna(0) # 实际税负率销项发票里的税金占比 out_tax agg[agg[direction] out].groupby(ent_id)[tax_sum].sum() profile[tax_rate] (out_tax / profile[sales_total]).replace([np.inf, -np.inf], np.nan) # 申报收入与发票销项收入的比值偏离过大的企业标记出来 merged profile.merge(sales_report, onent_id, howleft) merged[declared_vs_invoice] merged[declared_revenue] / (merged[sales_total] 1e-6) return merged需要说明的参数选择窗口为什么取3个月和6个月3个月平滑短期波动6个月覆盖一个季度账期加上缓冲。窗口太短会把季节性波动误判成经营下滑太长又会抹掉新企业的成长曲线。缺失值用 ffill 而不是 dropna老企业某月没开票可能只是结算周期问题新企业成立晚则天然缺数据。直接把缺失行删掉等于把新企业全踢出局。前向填充能保住宽表的完整性。税负率单独拿出来讲这在信贷圈子里有点玄学成分但风控确实在看这个指标。税负率异常低的企业要么在偷漏税要么收入是虚的后续评分时要给它降档。2.3 时间对齐和发票口径两个能毁掉整张表的细节第一个坑是时间。不同企业的数据起止时间往往不一样直接用全时段汇总做特征成立时间长的企业天然占优势。常见做法是给每家企业设一个统一的预测截止日特征窗口都从截止日往前推固定长度。我一般会额外写一个时间对齐函数把所有企业的数据截到同一个日期避免有的企业多看半年、有的少看半年。第二个坑是发票口径。作废票、红冲发票在明细里可能表现为负数或特殊状态清洗时一定要过滤。拿到的原始表里如果这些票混在正常销项里销项收入会被重复计算税负率也跟着失真。建议在构建特征前先做一次完整性核对检查项预期结果不合格时的处理企业ID是否唯一无重复查合并口径或拆分口径发票状态只剩有效票无作废、红冲按状态列过滤每家企业时间跨度差异在合理范围统一预测截止日后截取窗口进项与销项关系大部分进项小于销项进销比异常企业单独标记还有一个容易忽略的点把企业按数据活跃期分成两桶不足6个月的新企业单独处理。它们的特征只能用「近3个月是否有进项」「最近开票距今多少天」这类比率指标直接用月度均值会和老企业混在一起导致新企业评分全部偏低。这个小改动往往能把评分尾部表现拉回来不少。2.4 用三五家企业做人工核对特征工程做完别急着喂模型。我每次都会随机抽三到五家企业把它们的原始流水和特征值逐行核对一遍销项收入加总是否对得上连续活跃月份是否合理申报比对值有没有出现离谱的百倍量级。这一步看着土但抓出来的问题比任何自动化检查都多。有一次我发现某家企业的进项税额比销项税额还大查下来是发票状态没过滤干净红冲票混了进来修正之后税负率特征才恢复正常。这种错误如果带到模型里最后论文结论都是错的。3. 信用评分建模为什么这类题要放弃精确度、只追区分度3.1 准确率在这道题里没有意义先泼一盆冷水如果只看准确率一个「全都不违约」的预测器能拿到接近九成的分数。这道题违约样本占比很小模型天然面临严重的类别不均衡所以评判标准不是预测准不准而是能不能把违约企业和正常企业的分数拉开。评分模型输出的是一列连续分数而不是二分类标签区分度足够高后面才有做差异化额度和利率的空间。建模路线常用有三条标准评分卡、Logistic回归、聚类。评分卡在银行用得最多解释性强评委看着有代入感Logistic回归实现最简单是评分卡的简化版聚类可以处理没有信用记录的企业但要解释清楚聚出来的每一类是什么意思否则答辩容易被追问。C题数据量不大几百家企业的量级我建议先跑逻辑回归做基线时间富余再升级成分箱评分卡。3.2 端到端建模代码从训练到KS统计量from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split def build_score_model(X, y): # 有违约记录的企业才进训练集无记录企业另行处理 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy ) # class_weightbalanced让模型把违约样本当回事 model LogisticRegression(class_weightbalanced, C0.5, max_iter1000) model.fit(X_train, y_train) # 取违约概率作为分数来源而不是直接取0/1 y_prob model.predict_proba(X_test)[:, 1] return model, y_prob, y_test def ks_stat(y_true, y_score): # 按分数从高到低排序计算违约组与正常组累计分布的最大差距 df pd.DataFrame({y: y_true, score: y_score}) df df.sort_values(score, ascendingFalse).reset_index(dropTrue) pos df[y].cumsum() / max(df[y].sum(), 1) neg (1 - df[y]).cumsum() / max((1 - df[y]).sum(), 1) return (pos - neg).abs().max()参数和逻辑说明class_weightbalanced违约样本少普通逻辑回归会倒向多数类。这个参数按样本量倒数加权把少数类的损失放大训练出来的分数在违约组和正常组之间才有分隔。C0.5正则化强度。几百个样本的小数据集C 太大容易过拟合太小则把特征全压平0.5 是个合理的起点调参时按数量级试。为什么用 predict_proba 而不是 predict下一章的信贷策略需要连续分数来切额度档位二分类标签会把大量信息离散化。KS 统计量是这篇论文最该放进去的指标它表示排序后两组累计分布的最大差值0.3 以上说明模型有区分能力0.4 以上就很不错。评委只要看到你算 KS就知道你懂评分模型的核心逻辑。分数怎么转成 0-100 的信用分也顺手说一下。最直接的做法是把违约概率排个百分位再镜像一下让高概率对应低分数final_score (1 - y_prob.rank(pctTrue)) * 100这样得到的信用分近似均匀分布在 0-100 之间不受原始概率值偏移的影响。直接拿100 - y_prob*100也行但如果全部概率挤在 0.1 附近分数会堆在 90 以上毫无区分度百分位排名能解决这个问题。3.3 切分方式与阈值策略别让验证集偷看答案模型验证的切分方式我一直坚持「时间切分」而不是随机切分用前80%的时间段做训练后20%做验证。信贷业务本质是预测未来随机切分会把未来的数据混进训练集指标虚高且高得没有实际意义。阈值更不能默认 0.5。违约概率分布整体偏低0.5 作为阈值等于宣布几乎没有企业会违约。常见做法是取 KS 最大值对应的分数作为风险分界线或者用百分位的 70 分位作为预警线。论文里明确写清楚「阈值根据 KS 曲线选取」比丢一个默认阈值有说服力得多。另外有一部分没有信贷记录的企业进不了监督训练。我的做法是用有监督模型给它们打分做排序再叠加一条规则校验论文里写成「混合评估框架」逻辑上比硬分类站得住。提示如果违约样本太少连分层抽样都救不回来就不要硬做有监督模型。改用规则打分加上离群点检测写成混合信贷评估框架评委反而更认可。4. 信贷策略评分转额度利率的四步定价法与稳健性检验4.1 先定银行的三条底线再谈利润评分模型给出的是排序信贷策略给出的是真金白银的额度和利率。把分数映射成策略之前先写死三条底线不良率不能超过某上限单户额度不能超过企业经营能力利率不能低于资金成本。这三个约束是后面所有参数的上限来源。在C题场景里资金成本按年化 4.5% 左右估算比较常见那么优质客户利率应该落在 4.5% 附近风险客户往上加风险溢价。额度则锚定近六个月的销项收入不能给一个流水根本撑不住的金额。有了约束再看收益评分高给低利率和高额度评分低反过来这就是风险定价的基本逻辑。4.2 额度和利率的映射函数代码这一步把信用分转成可执行的信贷参数。我用的映射策略是三档再加一个拒绝区分段的好处是每一档的业务含义都能向评委说清。def credit_policy(final_score, sales_6m, ratio_cap0.4, base_rate0.045): # final_score: 0-100越高信用越好 # sales_6m: 近6个月销项收入用于限制单户额度 if final_score 60: return 0, None # 拒绝放贷 # 额度先按销项收入乘比例再用评分做折价 limit sales_6m * ratio_cap * (final_score / 100) if final_score 85: rate base_rate # 优质客户拿基准利率 elif final_score 75: rate base_rate 0.015 # 良好客户加150个基点 else: rate base_rate 0.03 # 65分以上的客户加300个基点 return round(limit, 2), round(rate, 4)参数怎么选额度的锚定基准是销项收入而不是利润。利润波动大且口径不统一销项收入来自发票可信度高。ratio_cap0.4 的意思是额度上限等于近6个月销项收入的 40%。真实信贷里这个比例对应「债务偿还比率」保守的机构会压到 0.3 以内。这个值的选取要配合后面的敏感性分析一起讲。利率等差递增是因为题目里没有违约损失率这类数据用分段映射更利于解释。每一档利率都对应一个风险区间评委看得出你是认真做了定价设计而不是随便套了个公式。拒绝线定在 60 分意味着评分后约 20% 的企业会被拒绝放贷这个比例跟真实银行的小微审批通过率大致相符。4.3 稳健性检验参数扰动与压力测试这一节是拉开论文差距的地方。模型定了不代表策略稳评委最爱追问「你的参数换一下结论会不会变」。我一般做两件事参数扰动和压力情景测试。import numpy as np rng np.random.default_rng(42) def robustness_check(final_score, sales_6m, n500): results [] for _ in range(n): cap rng.uniform(0.3, 0.5) # 额度比例扰动 ±25% base rng.uniform(0.035, 0.055) # 基准利率扰动 ±22% limits, rates credit_policy(final_score, sales_6m, cap, base) valid_rates [r for r in rates if r is not None] results.append([cap, base, limits.sum(), np.mean(valid_rates)]) return np.array(results)输出矩阵的四列分别是两个扰动参数和两个业务结果总额度、平均利率。我通常看两个结论总额度对参数扰动的波动幅度以及平均利率的稳定区间。如果参数扰动 ±25% 以内业务指标变化不超过 15%就说策略是稳健的这段写进论文就是一个独立的实证小节。压力测试的做法更粗暴把所有企业的销项收入统一打七折再跑一遍整套策略观察拒绝率上升多少、总额度缩水多少。评委看到这一页基本不会再问你「参数是不是凑出来的」因为你在主动演示边界条件。这部分的论文呈现建议用一张表列方向是参数变动范围、总额度变化率、平均利率变化率。三行就够写清楚基线值和扰动范围页脚注明随机种子保证可复现。很多队伍论文写了一整本却拿不出一张稳健性表格这是最可惜的丢分点。5. 常见问题排查从分箱到泄漏参赛中最容易翻车的五个坑5.1 时间跨度不一致老企业靠数据量碾压新企业现象评分模型跑完成立时间短的企业分数几乎全部压在尾部看起来像一群「坏客户」一刀切放贷额度全被拒掉。原因所有企业混在一张宽表里老企业天然有更多月份的销项记录聚合出的金额总额和活跃月数都更大模型把「数据量大」误当成了「经营实力强」。解决按我第2章说的把活跃期不足6个月的企业单独分桶用近3个月比率特征替代总量特征所有企业在同一个预测截止日下对齐时间窗。5.2 特征泄漏训练集漂亮得像开卷考试现象训练集AUC接近0.98验证集却一落千丈现场换数据直接就崩。原因特征里混进了「之后才知道」的信息。有人把全年的销项收入算完均值再去预测下半年是否违约等于拿答案做预测。解决坚持时间切分特征只允许使用预测截止日之前的数据。写代码时把特征工程封装成函数参数里传入截止日所有窗口计算都在截止日之前完成从机制上杜绝泄漏。5.3 类别不均衡0.5 阈值的致命默认值现象模型输出的违约预测几乎全是0查了类别分布才发现违约样本只占一小部分。原因没做类别加权模型学到的最优策略就是把所有样本预测成正常类再用默认0.5阈值切分违约企业全部被放走。解决训练时加class_weightbalanced评估时不看准确率看KS和AUC。另外写论文时明确写一句「决策阈值由KS曲线选取」而不是留在默认值这句话能拦住一半的追问。5.4 额度上限缺失给了流水根本撑不起的放款额现象某企业信用分不错模型给了一笔大额贷款但一对照销项流水额度相当于月收入的3倍按这个金额根本还不出来。原因直接用评分映射额度忘了给额度设置偿付能力上限。解决额度必须等于销项收入乘以倍数系数。我通常把系数范围控制在0.3到0.5并且在论文里把额度公式写清楚附上一句「额度上限受企业近6个月销项收入约束」这是风控常识评委看了不会挑毛病。5.5 论文没有稳健性检验答辩被追问就卡壳现象评委问「你的额度比例从0.4改成0.6结论还成立吗」答辩人当场愣住。原因全文只贴了模型训练效果没做任何参数扰动分析策略的边界完全没交代。解决补上第4章的扰动实验哪怕只改额度比例和基准利率两个参数生成一张参数-结果表说服力都会完全不同。从那以后我做这类题都会提前跑一遍随机种子固定的扰动数据放论文附录里都是加分项。6. 进阶技巧从C题到通用风控的复用要点6.1 分箱与IV值把逻辑回归升级成标准评分卡C题的数据量不大但特征分箱这个技巧可以直接复用。分箱能处理非线性关系还能把缺失值单独成箱解释性比连续变量更好。IV值用于筛选特征低于0.02的特征直接丢掉0.02到0.1是弱特征0.1到0.3算中等超过0.3才是强特征。用这个标准去筛C题里构造的十几个特征剩下来的通常只有销项稳定度和申报偏离度这两个筛选过程本身就能写进论文的特征工程章节。def woe_iv(x, y, bins10): df pd.DataFrame({x: x, y: y}) df[bin] pd.qcut(df[x], bins, duplicatesdrop) agg df.groupby(bin, observedTrue).agg( good(y, lambda s: (s 0).sum()), bad(y, lambda s: (s 1).sum()) ) agg[woe] np.log((agg[bad] / agg[bad].sum()) / (agg[good] / agg[good].sum() 1e-6)) agg[iv] ((agg[bad] / agg[bad].sum()) - (agg[good] / agg[good].sum())) * agg[woe] return agg[iv].sum()6.2 与真实信贷数据的差异C题是静态快照真实风控是持续更新的流式数据两者差距明显心里要有数。维度C题数据真实生产环境样本量几百家企业几万到几十万是否含法人征信无通常有数据形态静态快照持续更新特征维度若干发票字段征信、工商、司法等多源模型要求一版论文即可可监控、可解释C题练手最大的价值是让你完整走通「数据清洗—评分—定价—检验」这条链真实环境里这条链会更长但核心逻辑不变。6.3 固定工作流拿到信贷数据后的五步检查整理一下我拿到任何一份信贷数据都会强制走一遍第一步数据字典逐字段核对搞清楚每个字段的单位和口径第二步画出时间轴标出每个样本的预测截止日第三步先跑规则基线比如销项下降超过30%直接拒绝再用模型第四步所有特征封装成独立函数参数写死保证可复现第五步论文里的每个结论都要能找到对应的代码输出。这套流程看着笨但能避免第九版数据覆盖第八版时把结论带偏。从那以后我每次做信贷决策题都把这条链完整走一遍再没出现过回测良好、现场翻车的情况。这套方法论希望对你有帮助。本文还有配套的精品资源点击获取
RELATED

相关推荐

C语言终端表格打印库:按字符显示宽度实现中文对齐

C语言终端表格打印库:按字符显示宽度实现中文对齐

简介:终端中以表格形式整齐打印包含中文的字符串,是不少C语言初学者都会遇到的常见痛点。这份示例资源专门解决C语言表格对齐打印问题,在Ubuntu 14.04 64位下完成测试,通过处理中文字符显示宽度,避免了字符错位&#x…

📅 2026/10/20 19:25:10
网页转可引用知识:Chatbot联网工具的可信架构设计

网页转可引用知识:Chatbot联网工具的可信架构设计

1. 项目概述:为什么我们需要“把网页变成可引用知识”你有没有遇到过这样的场景:在写一份技术方案时,突然需要确认某个开源库的最新 API 参数;在准备行业分析报告时,想快速引用权威机构刚发布的白皮书核心结论&#xf…

📅 2026/10/20 19:25:10
智能化小区网络规划全解析:从拓扑选型到落地避坑指南

智能化小区网络规划全解析:从拓扑选型到落地避坑指南

简介:面向智能化小区网络规划毕业设计选题的论文资源,适合网络工程、智能建筑方向的学生及需要完成课程设计者参考。内容以小区智能化系统为背景,依次覆盖宽带网络分类、OSI七层参考模型,并逐一分析中继器、网桥、路由器、网关、集…

📅 2026/10/20 19:20:09
MORE NEWS

更多资讯

📰

SolidWorks二次开发模板:基于.NET Framework的可交付插件工程化实践

简介:本资源是一套开箱即用的SolidWorks C#二次开发模板工程,面向机械设计工程师、CAD自动化开发者及高校相关专业学习者,解决从零搭建插件项目、理解SDK交互机制与快速实现功能扩展的入门难题。压缩包含99个文件,涵盖18个核心C#源…

📰

Linux磁盘I/O监控:iostat与iotop实战排查

1. 为什么需要监控磁盘 I/O:从一次“查不出原因的卡顿”说起你有没有遇到过这种情况:应用响应突然变慢,CPU 和内存占用却都在正常范围内,看日志也没报错,可服务就是像陷在泥潭里一样。排查到最后才发现,罪魁…

📰

一文梳理AI Infra知识全景:算力、存储、训练、推理与平台

做AI项目做了几年,我一直有个很尴尬的处境:模型结构、损失函数、调参技巧这些聊起来头头是道,可一旦扯到GPU集群怎么规划、数据管线为什么卡住、推理服务为什么线上长尾延迟爆炸,就有点心虚。直到有一次亲手把一个训练任务搞挂&am…

📰

从模糊命名到清晰边界:以rea为例谈代码可维护性重构

1. 从“rea”这个标题说起:一个被低估的缩写背后藏着什么第一次看到“rea”这个标题的时候,我承认自己愣了几秒。没有正文,没有关键词,没有摘要描述,就孤零零三个字母。但恰恰是这种极简的输入,反而让我觉得…

📰

Hive实现树形结构展开:三种方案对比与工程实践

1. 树形结构为什么要展开:从组织架构到评论盖楼的实际场景很多数仓同学第一次看到“hive实现树形结构展开”这个需求时,心里想的都是:这不就是递归查询吗?但真正动手就会发现,Hive 在这方面比常见的关系型数据库麻烦得…

📰

计算机图形学速通指南:从渲染管线到软渲染器的全景地图

计算机图形学这个领域有个挺有意思的现象:网上的教程多到看不完,但能把一个三角形从顶点数据变成屏幕上像素这件事从头到尾讲清楚的人,少之又少。我准备写一套《计算机图形学速通指南笔记》的时候,一直在想第一篇到底该从哪讲起。…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬