数字普惠金融2026 Courseware

第一章

贝叶斯方法与数字普惠金融的概率决策

概率决策、先验信息与动态更新

本章以朴素贝叶斯为重点:从先验、似然与后验的直觉,到小微信贷的完整手算案例,再到可直接运行的 Python 风险筛查与后验推理。贝叶斯线性回归和层次模型保留为理解不确定性与跨地区信息共享的延伸。

01

贝叶斯思想的精髓

贝叶斯方法可以先不要从公式开始,而是从“人怎样不断修正判断”开始理解。我们每天都在做贝叶斯更新:医生看病、挑餐馆、判断一个店铺靠不靠谱,背后都是先有一个初步判断,再根据新证据不断调整。

例子一:医生看病就是一个贝叶斯过程

你走进诊室,医生还没有做任何检查,但他已经有一个初步判断。比如看到你脸色不好、精神差、年龄和季节背景,他可能会先猜:感冒、肠胃炎、过敏、流感,或者别的问题。这不是乱猜,而是根据经验形成的初始概率,这就是先验概率。

接下来医生开始问症状:有没有发烧?有没有咳嗽?有没有腹痛?最近有没有吃不干净的东西?每一个症状都不是孤立信息,而是和某些疾病更相关。比如高烧和流感的关联更强,腹痛和肠胃炎的关联更强。这种“如果是某种病,出现这些症状的可能性有多大”,就是似然函数。

医生把先验判断和症状证据结合起来,就会得到新的判断:某些疾病的可能性下降,某些疾病的可能性上升。这个更新后的判断就是后验概率。后验概率最高的病,通常会成为医生优先检查或治疗的方向。

先验

医生进门时根据经验形成的初步疾病判断

似然

在某种疾病下,观察到发烧、咳嗽、腹痛等症状的可能性

后验

综合初步判断和症状之后,对不同疾病可能性的重新排序

例子二:选择餐馆也可以看成贝叶斯更新

假设你面前有五家餐馆,一开始你完全不了解它们。最自然的先验就是每家都一样好,每家被选中的概率都是五分之一。

然后你开始观察证据:哪家装修更干净?哪家排队的人更多?美团评分高不高?评论里有没有反复提到服务差或菜品不新鲜?这些证据会改变你对每家餐馆的判断。

如果一家店评分高、顾客多、评论稳定,而且环境不错,那么这些证据在“这家店值得吃”这个假设下出现的概率更高。于是它的后验概率会上升。最后你并不是凭感觉随便选,而是在用新信息更新每家店“值得选择”的概率。

先验

五家餐馆一开始都不了解,每家概率都是 1/5

证据

装修、人气、评分、评论、距离、价格

后验

综合证据后,每家餐馆“值得去”的概率不再相同

p(θ∣y)=p(y∣θ)p(θ)p(y)∝p(y∣θ)p(θ)p(\theta \mid y)=\frac{p(y\mid \theta)p(\theta)}{p(y)} \propto p(y\mid \theta)p(\theta)
  • 其中 θ\theta 表示未知参数或状态,yy 表示观测到的数据。先验 p(θ)p(\theta) 记录数据到来前的判断,似然 p(y∣θ)p(y\mid\theta) 描述某个参数下观察到数据的可能性,后验 p(θ∣y)p(\theta\mid y) 是更新后的认知。
  • 如果把医生看病放进这个公式,疾病就是未知状态,症状就是观察到的数据。医生最初的经验判断是先验,症状与疾病之间的匹配程度是似然,问诊之后重新排序的疾病可能性就是后验。
  • 如果把选餐馆放进这个公式,餐馆是否值得去就是未知状态,评分、人气、装修和评论就是观察到的数据。你最初平均分配概率,后来根据证据重新排序,这也是贝叶斯更新。
  • 在农村信贷、小微企业融资和早期风险识别中,道理完全一样:客户是否可靠是未知状态,流水、还款记录、经营年限、地区产业情况是证据。贝叶斯框架允许把经验判断和新增数据合在一起。
怎么理解

先验不是偏见,而是“在没有看到新证据之前的合理起点”;似然不是结论,而是“这个证据更像是哪种情况会出现”;后验才是把两者合在一起之后的新判断。

普惠金融例子

信贷经理面对一个没有完整征信记录的农户,也会先有初步判断:当地作物收成、合作社口碑、过往小额借款表现。随后再看流水、订单、还款行为这些证据,最后形成新的授信判断。

课堂追问

在小样本普惠金融中,怎样区分“合理先验”和“经验偏见”?

02

似然、似然函数与极大似然:从“匹配程度”到“最像数据的参数”

“似然”最容易被误解成“概率的另一种说法”。它们使用的条件概率形式看起来相同,却在回答相反方向的问题:概率先固定原因,再问结果会不会出现;似然先固定已经看到的结果,再比较哪一种原因或参数更能解释它。

概率:从原因推结果

先假定“患者得的是流感”,再问“出现高烧的概率是多少”。这里疾病固定,症状是可能变化的结果:P(高烧 | 流感)。

似然:从结果比原因

现在高烧已经观察到。把“流感”“普通感冒”等不同解释逐一代入,比较哪一种解释下高烧更常见。数值仍来自 P(高烧 | 疾病),但它此时是对疾病解释力的比较。

似然函数:让参数移动

当候选对象不是几个疾病类别,而是连续参数 p(例如真实逾期率)时,把观察到的数据固定,让 p 从小到大移动;每一个 p 都对应一个似然值,整条曲线就是似然函数。

用医生问诊理解“证据更支持谁”

假设医生观察到“高烧”。下面的数并不构成真实诊断规则,只用于区分概率、似然和后验;真实医疗决策必须由合格医生完成。

候选解释先验:进门前的经验判断高烧出现的概率高烧带来的似然贡献先验 × 似然
流感10%P(高烧 | 流感) = 80%0.800.10 × 0.80 = 0.080
普通感冒40%P(高烧 | 普通感冒) = 20%0.200.40 × 0.20 = 0.080

单看症状,0.80 比 0.20 大,说明高烧更像流感会出现的证据;但医生还不能跳到“肯定是流感”,因为普通感冒的先验更高。相乘后两者暂时同为 0.080。继续询问咳嗽、肌肉酸痛、接触史等症状,才会继续更新。似然负责“证据更像谁”,后验才负责“综合之后更相信谁”。

用餐馆选择理解“不要被一个证据带走”

看到一家店顾客很多,不能直接等同于“它一定值得吃”。应该比较:客人多在不同解释下分别有多常见。

候选解释观察到“顾客很多”的概率如何读这个数
这家店值得去P(顾客多 | 值得去) = 75%口味、卫生和口碑好时,客流旺盛较常见。
这家店并不值得去P(顾客多 | 不值得去) = 30%也可能是位置好、出餐慢、促销强,因此并非不可能。

这条证据的似然比为 0.75 ÷ 0.30 = 2.5:它让“值得去”这个解释相对更有说服力,但还应继续看评分、近期差评、价格和排队速度。金融风控同样如此:一笔逾期是证据,不是标签;要比较它在不同经营状况、地区冲击和还款能力下出现的可能性。

从几个解释到一个连续参数

设某个小微信贷网点过去发放了 60 笔贷款,其中观察到 9 笔逾期。记 p 为该网点在相似条件下的真实逾期概率。数据已经固定为“60 笔里有 9 笔逾期”;我们不再让数据变化,而让 p 取不同值,比较哪一个值最容易产生这组数据。

L(p | y = 9, n = 60) ∝ p⁹ × (1 − p)⁵¹

这就是二项分布下的似然函数。p⁹ 对应 9 次逾期都发生,(1 − p)⁵¹ 对应其余 51 次没有逾期。曲线高并不表示“p 本身的概率高”,而表示“如果真实逾期率取这个 p,眼前这 60 笔记录出现得更自然”。

极大似然估计(MLE)到底在做什么?

  1. 固定观察结果:这里是 60 笔中恰好 9 笔逾期。
  2. 列出所有候选参数:令真实逾期率 p 可以是 5%、10%、15%、20%……
  3. 逐个比较似然:把每一个 p 代入 L(p | y),看哪一个最容易产生“9 / 60”这组结果。
  4. 选曲线最高点:最高点就是极大似然估计,p̂MLE = 9 / 60 = 15%。它是“最像这批数据的参数”,不是对未来的保证。

MLE 与贝叶斯更新差在哪里?

  1. MLE:只让这 60 笔数据说话,选择似然最高的 p = 15%。
  2. 贝叶斯:除了数据,还明确写入历史经验。例如先验可表示为“过去类似网点的逾期率通常不高”。
  3. 后验:把先验与似然相乘并归一化,得到一条新的参数分布;本例图中后验均值约为 13.8%。
  4. 何时重要:样本很少、区域新设或数据质量有限时,先验会防止仅凭几条记录做出过度极端的判断。
绘制似然函数与 MLE · Python
import numpy as np
import matplotlib.pyplot as plt

y, n = 9, 60                 # 已观察到:60 笔中有 9 笔逾期
p = np.linspace(0.001, 0.45, 600)

# 对数形式更稳定;减去最大值后,曲线最高点仍为 1
log_likelihood = y * np.log(p) + (n - y) * np.log(1 - p)
relative_likelihood = np.exp(log_likelihood - log_likelihood.max())
p_mle = y / n

print(f"极大似然估计 p_MLE = {p_mle:.2%}")
plt.plot(p, relative_likelihood, color="#1f6b65", linewidth=2.5)
plt.axvline(p_mle, color="#b65a2b", linestyle="--")
plt.xlabel("候选真实逾期率 p")
plt.ylabel("相对似然")
plt.title("60 笔中观察到 9 笔逾期时的似然函数")
plt.show()
极大似然估计 p_MLE = 15.00%
60笔贷款中观察到9笔逾期时的似然函数、极大似然点、先验和后验分布图
左图固定“9 / 60”这组数据,让候选逾期率 p 移动;曲线最高点在 15%。右图进一步展示:贝叶斯方法把历史先验与似然合并为后验分布,因此不仅给出一个点,也保留不确定性的范围。
一句话记忆

概率问“如果原因是真的,结果会不会出现”;似然问“结果已经出现,哪种原因或参数更能解释它”。

普惠金融例子

某村出现 3 笔短期逾期时,先用似然比较“季节性回款延迟”“局部灾害冲击”“客户长期偿债压力”等解释,再结合历史和新增信息更新判断。

避免误读

不要把“似然最高”说成“参数发生的概率最高”。频率学派的 MLE 是优化规则;只有引入先验并归一化后,才得到参数的后验概率分布。

03

贝叶斯定理与全概率公式

贝叶斯公式真正想表达的是一个简单逻辑:不要只看证据本身,还要看这个证据更支持哪一种解释。同样是“发烧”,它可能支持感冒,也可能支持流感;同样是“店里人多”,可能说明好吃,也可能只是因为位置好或排队慢。

p(y)=∑k=1Kp(y∣θk)p(θk)p(y)=\sum_{k=1}^{K}p(y\mid \theta_k)p(\theta_k)
  • 全概率公式告诉我们:同一个观测结果可能由多个潜在状态产生。医生不能看到发烧就只判断一种病,风控人员也不能看到逾期就只判断客户恶意违约。
  • 概率 p(θ∣y)p(\theta\mid y) 是在观测数据后对状态的判断;似然 p(y∣θ)p(y\mid\theta) 是在给定状态下数据出现的可能性。二者不能混用。
  • 基准概率谬误是金融应用中的常见错误:只关注一个证据很显眼,却忽略事件本身的基础发生率。例如欺诈比例很低时,即使模型精度较高,也可能产生大量误报。
  • 回到餐馆例子:一家店排队很长是一个证据,但你还要问,排队长在“好吃”这个假设下常见吗?在“出餐慢”这个假设下是不是也常见?贝叶斯思维要求我们比较不同解释,而不是被单一证据带走。
怎么理解

分母不是数学装饰,它提醒我们同一个现象可能有多种解释。金融风控中,不能看到一个逾期就直接推断客户恶意违约。

普惠金融例子

农户短期逾期可能是销售回款延迟、自然灾害、家庭支出冲击,也可能是长期偿债能力下降。贝叶斯分析要求把这些可能性都放进同一个概率框架。

课堂追问

如果某地区突然出现集中逾期,应该先怀疑客户质量,还是先检查外部冲击?

04

朴素贝叶斯筛查器

朴素贝叶斯在机器学习教材中通常被称为“分类器”,但在普惠金融风控教学中,更适合把它理解为“筛查器”:模型先给出高风险后验概率,再由教师或业务人员明确设置复核阈值和代价权衡。

先弄清楚:什么是“朴素”,什么是“贝叶斯”,为什么要做“筛查”

“贝叶斯”指的是它用贝叶斯公式比较不同类别的后验概率。比如客户可能是“低风险”或“高风险”,模型会分别计算这两个状态在现有证据下的相对可能性。

“朴素”指的是一个简化假设:在给定类别之后,各个特征之间暂时当作互相独立。比如在判断客户风险时,把账户余额、信用历史、储蓄水平、就业年限分别看成独立证据,然后把这些条件概率相乘。

“筛查”强调的是业务动作。模型输出的不是“必须拒绝”或“必须通过”,而是一个高风险后验概率。只有当这个概率超过事先写清楚的阈值,例如 10%,才进入人工复核或补充材料流程。

贝叶斯

比较不同风险状态的后验概率

朴素

给定风险状态后,暂时把各特征当成独立证据

筛查

按明确阈值决定是否进入人工复核

p(Ck∣x1,…,xd)∝p(Ck)∏j=1dp(xj∣Ck)p(C_k\mid x_1,\ldots,x_d) \propto p(C_k)\prod_{j=1}^{d}p(x_j\mid C_k)
  • 公式中的 CkC_k 是候选类别,例如“好信用/坏信用”或“通过/复核”。x1,…,xdx_1,\ldots,x_d 是观察到的特征,例如账户状态、信用历史、储蓄水平、就业年限。
  • 在信用审批中,特征可以包括还款记录、交易频率、收入稳定性、经营年限和地区产业结构。模型给出的每一项条件概率都可以解释为一个证据贡献。
  • 当某个特征组合在训练样本中没有出现时,需要使用拉普拉斯平滑:p^(xj=v∣Ck)=nv,k+αnk+αm\hat p(x_j=v\mid C_k)=\frac{n_{v,k}+\alpha}{n_k+\alpha m}。这可以避免某个概率为零导致整体后验归零。
  • 朴素贝叶斯特别适合作为基准模型。复杂模型若无法显著超过这个透明基准,说明数据、标签或特征工程可能存在问题。

案例 A:天气与是否打球的 14 条教学数据

这是机器学习课程中常见的 Play Tennis / Play Golf 小数据。它不是金融数据,但很适合第一次手算朴素贝叶斯,因为变量都是分类变量。

编号天气温度湿度风是否打球
1SunnyHotHighWeakNo
2SunnyHotHighStrongNo
3OvercastHotHighWeakYes
4RainMildHighWeakYes
5RainCoolNormalWeakYes
6RainCoolNormalStrongNo
7OvercastCoolNormalStrongYes
8SunnyMildHighWeakNo
9SunnyCoolNormalWeakYes
10RainMildNormalWeakYes
11SunnyMildNormalStrongYes
12OvercastMildHighStrongYes
13OvercastHotNormalWeakYes
14RainMildHighStrongNo

案例 A 的频数表:先数类别,再数条件概率

现在预测一个新样本:Sunny、Cool、High、Strong。我们分别计算它属于 Yes 和 No 的相对后验分数。

概率项Yes 中的频数No 中的频数条件概率
类别先验Yes = 9No = 5p(Yes)=9/14,  p(No)=5/14p(\mathrm{Yes})=9/14,\;p(\mathrm{No})=5/14
天气 = Sunny2 / 93 / 5p(Sunny∣Yes)=2/9,  p(Sunny∣No)=3/5p(\mathrm{Sunny}\mid \mathrm{Yes})=2/9,\;p(\mathrm{Sunny}\mid \mathrm{No})=3/5
温度 = Cool3 / 91 / 5p(Cool∣Yes)=3/9,  p(Cool∣No)=1/5p(\mathrm{Cool}\mid \mathrm{Yes})=3/9,\;p(\mathrm{Cool}\mid \mathrm{No})=1/5
湿度 = High3 / 94 / 5p(High∣Yes)=3/9,  p(High∣No)=4/5p(\mathrm{High}\mid \mathrm{Yes})=3/9,\;p(\mathrm{High}\mid \mathrm{No})=4/5
风 = Strong3 / 93 / 5p(Strong∣Yes)=3/9,  p(Strong∣No)=3/5p(\mathrm{Strong}\mid \mathrm{Yes})=3/9,\;p(\mathrm{Strong}\mid \mathrm{No})=3/5

案例 B:UCI German Credit 真实信用风险数据的课堂版频数表

UCI German Credit 数据有 1000 条样本、20 个特征,目标是把客户标记为 Good 或 Bad credit risk。这里抽取 4 个容易解释的分类变量做手算示范。

特征取值Good 频数 / 700Bad 频数 / 300课堂解释
A11:支票账户余额 < 0 DM139135账户状态偏紧张
A32:既有贷款目前都按时还361169普通信用历史
A61:储蓄 < 100 DM386217储蓄缓冲较低
A72:当前就业 < 1 年10270就业稳定性较弱

案例 A 手算:Sunny、Cool、High、Strong 时是否打球?

  1. 第一步,先验概率:p(Yes)=9/14p(\mathrm{Yes})=9/14,p(No)=5/14p(\mathrm{No})=5/14。这表示在没有看天气之前,14 天里有 9 天打球、5 天不打球。
  2. 第二步,计算 Yes 的相对后验分数:Score⁡(Yes)=914×29×39×39×39≈0.00529\operatorname{Score}(\mathrm{Yes})=\frac{9}{14}\times\frac{2}{9}\times\frac{3}{9}\times\frac{3}{9}\times\frac{3}{9}\approx0.00529
  3. 第三步,计算 No 的相对后验分数:Score⁡(No)=514×35×15×45×35≈0.03429\operatorname{Score}(\mathrm{No})=\frac{5}{14}\times\frac{3}{5}\times\frac{1}{5}\times\frac{4}{5}\times\frac{3}{5}\approx0.03429
  4. 第四步,比较两个分数。因为 Score⁡(No)>Score⁡(Yes)\operatorname{Score}(\mathrm{No})>\operatorname{Score}(\mathrm{Yes}),所以模型预测“不打球”。
  5. 这里的“朴素”体现在:天气、温度、湿度、风四个证据被分别计算,然后直接相乘。现实里它们可能相关,但课堂上这样算最透明。

案例 B 手算:把朴素贝叶斯迁移到信用风险

  1. 现在看一个真实信用数据中的课堂版客户画像:支票账户余额 < 0 DM;既有贷款目前都按时还;储蓄 < 100 DM;当前就业 < 1 年。
  2. 第一步,类别先验来自 1000 条真实样本:p(Good)=700/1000=0.7p(\mathrm{Good})=700/1000=0.7,p(Bad)=300/1000=0.3p(\mathrm{Bad})=300/1000=0.3。
  3. 第二步,计算 Good 的相对后验分数:Score⁡(Good)=0.7×139700×361700×386700×102700≈0.00576\operatorname{Score}(\mathrm{Good})=0.7\times\frac{139}{700}\times\frac{361}{700}\times\frac{386}{700}\times\frac{102}{700}\approx0.00576
  4. 第三步,计算 Bad 的相对后验分数:Score⁡(Bad)=0.3×135300×169300×217300×70300≈0.01284\operatorname{Score}(\mathrm{Bad})=0.3\times\frac{135}{300}\times\frac{169}{300}\times\frac{217}{300}\times\frac{70}{300}\approx0.01284
  5. 第四步,把两个分数归一化,得到课堂版解释:p(Good∣x)≈31.0%p(\mathrm{Good}\mid x)\approx31.0\%,p(Bad∣x)≈69.0%p(\mathrm{Bad}\mid x)\approx69.0\%。因此模型会把这个客户放入较高风险或需要复核的队列。
  6. 注意:这里的 Bad 是数据集标签,不是道德判断;在普惠金融中更不能直接等同于拒贷。更合理的做法是进入人工复核、补充材料、调整额度或设计担保机制。
金融应用提示

普惠金融中的农村信贷模型可以先用朴素贝叶斯建立“低成本可解释筛查器”,再对边界样本交由更复杂模型或人工复核。

怎么理解

“朴素”不是“低级”,而是用一个强假设换取透明、快速和小样本可用。它适合做第一道风险筛查。

普惠金融例子

例如对新申请的小微商户,可以把经营年限、月均流水、历史还款、行业景气度分别作为证据,快速估算高风险概率,再把边界样本交给人工复核。

课堂追问

如果两个特征高度相关,例如月流水和收款笔数,朴素贝叶斯的独立性假设会带来什么问题?

05

用 Python 做朴素贝叶斯筛查与后验推理

前面的表格让你看见了公式在做什么;下面把同一件事交给 Python。代码沿用本章配套 c01-code.html 的练习主线:10,000 条合成信用记录、以信用评分构造课堂标签、训练高斯朴素贝叶斯、输出后验概率,并用明确的阈值完成风险筛查。为公开静态站点,数据只保留去标识化数值字段。

先分清三件事

模型先计算 P(低风险 | 特征) 与 P(高风险 | 特征);标签只是按某个阈值得到的简写;业务动作则可能是常规处理、进入人工复核、要求补充材料。三者不能混为一谈,尤其不能把“高风险”直接等同于拒贷。

自学附件:完整代码实践

本节的完整 Notebook 导出页面已作为附件放在课件中。它包含数据读取、贝叶斯筛查、后验概率、可视化和实践建议,适合课后按顺序自学。点击下方链接可在新页面打开。

打开 c01-code.html 完整代码实践

配套教学数据:去标识化的合成信用记录

原始笔记中的数据为合成数据;此处删去姓名、出生日期、城市和职业等不必要字段。high_risk = 1 的课堂定义为 CREDIT_SCORE < 650,仅用于演示,不是现实机构的授信规则。

字段含义单位 / 类型模型角色
applicant_id重新生成的教学编号文本只用于定位,不进入模型
AGE / EXP_YRS年龄 / 工作年限年连续特征
INCOME / SAVINGS / DEBT_TOTAL年收入 / 储蓄 / 未偿债务元连续特征
CC_UTIL信用额度使用率0–1连续特征
LATE_30 / LATE_60近 24 个月 30+ / 60+ 天逾期次数次数连续特征
NUM_CC / ACCT_AGE信用卡数 / 最早账户存续时间张 / 月连续特征
high_risk课堂标签0 或 1预测目标
下载去标识化教学数据(CSV)

读取数据:先核验规模、字段和基础率

把 CSV 下载后放在 Notebook 同级目录的 data 文件夹。Path 用来明确文件位置;features 明确哪些列可以成为证据,刻意不把编号放入模型。

读取与核验 · Python
from pathlib import Path
import pandas as pd

DATA_PATH = Path("data/credit_nb_teaching.csv")
df = pd.read_csv(DATA_PATH)

features = [
    "AGE", "INCOME", "EXP_YRS", "SAVINGS", "DEBT_TOTAL",
    "CC_UTIL", "LATE_30", "LATE_60", "NUM_CC", "ACCT_AGE",
]
y = df["high_risk"]

print("数据维度:", df.shape)
print("高风险样本比例:", f"{y.mean():.2%}")
print(df[["applicant_id", *features[:4], "high_risk"]].head())
数据维度: (10000, 12) 高风险样本比例: 1.73% applicant_id AGE INCOME EXP_YRS SAVINGS high_risk 0 A0001 56 56909.45 38 621744.90 0 1 A0002 32 68834.83 13 105990.18 0 …
把类别比例画出来 · Python
import matplotlib.pyplot as plt

counts = y.value_counts().sort_index()
labels = ["低风险(0)", "高风险(1)"]
plt.bar(labels, counts.values, color=["#6f9e8d", "#b65a2b"])
plt.ylabel("样本数")
plt.title("教学数据中的类别不平衡")
for i, value in enumerate(counts.values):
    plt.text(i, value, f"{value:,}({value / len(y):.2%})", ha="center", va="bottom")
plt.show()
去标识化教学信用数据中低风险和高风险标签的数量及占比柱状图
运行上方代码后的图形输出。数据类别明显不平衡,因此“准确率很高”不能证明模型已经识别出高风险申请人。
第一项重要发现

1.73% 意味着每 100 人中约只有 2 人被标为高风险。若模型把所有人都预测为低风险,准确率仍会很高。因此这里不能只看 accuracy;还要看召回率、精确率、AUC 和被送去复核的人数。

训练高斯朴素贝叶斯:为每一个类别估计每一项证据

GaussianNB 是数值特征场景下的朴素贝叶斯实现。fit(X_train, y_train) 会按类别估计各列的均值和方差,同时记录类别先验;predict_proba(X_test) 的每一行都给出两个相加为 1 的后验概率。stratify=y 确保测试集保留与原数据相近的高风险比例。

训练与默认标签 · Python
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import accuracy_score, recall_score, roc_auc_score

X_train, X_test, y_train, y_test = train_test_split(
    df[features], y, test_size=0.30, random_state=42, stratify=y
)
model = GaussianNB(var_smoothing=1e-9)
model.fit(X_train, y_train)

pred_default = model.predict(X_test)
prob_high_risk = model.predict_proba(X_test)[:, 1]

print("训练集 / 测试集:", X_train.shape[0], "/", X_test.shape[0])
print("类别先验:", model.class_prior_.round(4))
print("AUC:", round(roc_auc_score(y_test, prob_high_risk), 4))
print("默认阈值下的 accuracy:", round(accuracy_score(y_test, pred_default), 4))
print("默认阈值下的 recall:", round(recall_score(y_test, pred_default, zero_division=0), 4))
训练集 / 测试集: 7000 / 3000 类别先验: [0.9827 0.0173] AUC: 0.8291 默认阈值下的 accuracy: 0.9827 默认阈值下的 recall: 0.0
怎样读这个结果

AUC 为 0.8291,说明模型对风险概率有一定区分能力;但默认 0.50 阈值下一个高风险客户也没有被标出。不是代码错误,而是类别极不平衡,后验概率超过 50% 的条件很苛刻。

普惠金融含义

不要把默认标签为低风险理解成没有风险。对于首贷、缺少征信记录或额度较大的申请,后验概率本身比 0/1 标签更有用。

需要自问

漏掉一位高风险客户的成本,与把一位正常客户送去人工复核的成本,哪一个更高?阈值应由这个业务问题决定。

查看 ROC 曲线与预测概率分布 · Python
from sklearn.metrics import roc_curve
import matplotlib.pyplot as plt

fpr, tpr, _ = roc_curve(y_test, prob_high_risk)
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
axes[0].plot(fpr, tpr, color="#1f6b65", label="GaussianNB")
axes[0].plot([0, 1], [0, 1], "--", color="#9aa1a8")
axes[0].set(xlabel="假阳性率", ylabel="真阳性率", title="ROC 曲线")
axes[0].legend()
axes[1].hist(prob_high_risk[y_test == 0], bins=30, alpha=.7, label="低风险")
axes[1].hist(prob_high_risk[y_test == 1], bins=20, alpha=.8, label="高风险")
axes[1].set(xlabel="预测的高风险后验概率", ylabel="样本数", title="后验概率分布")
axes[1].legend()
plt.tight_layout()
plt.show()
高斯朴素贝叶斯模型的ROC曲线和高风险后验概率分布图
运行上方代码后的图形输出。左图考察不同阈值下的区分能力;右图显示大多数样本的高风险后验都很低,这与类别不平衡相互印证。

后验推理:对一位新申请人读出筛查概率

下面这位申请人默认标签为低风险,因为其高风险后验约为 14.61%,低于 50%。但它远高于训练样本中的 1.73% 高风险先验;若使用“10% 进入人工复核”的规则,他应进入复核队列,而不是被自动放行。

单个申请人的后验推理 · Python
new_application = pd.DataFrame([{
    "AGE": 32, "INCOME": 75000, "EXP_YRS": 6, "SAVINGS": 120000,
    "DEBT_TOTAL": 28000, "CC_UTIL": 0.28, "LATE_30": 0,
    "LATE_60": 0, "NUM_CC": 2, "ACCT_AGE": 54,
}])
posterior = model.predict_proba(new_application)[0]
print(f"低风险后验概率:{posterior[0]:.2%}")
print(f"高风险后验概率:{posterior[1]:.2%}")
print("默认标签:", "高风险" if model.predict(new_application)[0] == 1 else "低风险")
print("10% 复核规则:", "进入人工复核" if posterior[1] >= 0.10 else "常规处理")
低风险后验概率:85.39% 高风险后验概率:14.61% 默认标签: 低风险 10% 复核规则: 进入人工复核
把新申请人的后验画成柱状图 · Python
import matplotlib.pyplot as plt

labels = ["低风险后验", "高风险后验"]
colors = ["#6f9e8d", "#b65a2b"]
plt.bar(labels, posterior, color=colors)
plt.axhline(0.10, color="#8b4f24", linestyle="--", label="10% 复核阈值")
plt.ylim(0, 1)
plt.ylabel("后验概率")
plt.title("单个申请人的模型后验输出")
plt.legend()
plt.show()
一位新申请人的低风险与高风险后验概率柱状图,带10%人工复核阈值
运行上方代码后的图形输出。默认的 50% 标签规则给出“低风险”,但 14.61% 高风险后验超过了 10% 的人工复核线;这正是“概率、筛查标签和业务动作要分开”的例子。

把分类改成筛查:明确写出阈值与代价

阈值不是模型自动给出的真理,而是一项可审计的业务设置。本例明确采用 10% 高风险后验概率 作为进入人工复核的教学阈值:若 P(高风险 | 特征) >= 10%,则进入复核;否则常规处理。这里的代价也必须写清楚:漏筛高风险客户会带来坏账和后续催收成本;误筛正常客户会带来等待时间、人工审核成本和金融服务可得性的损失。真实应用还必须加入审核能力、客诉、拒贷申诉与群体公平性检查。

阈值筛查与评估 · Python
from sklearn.metrics import confusion_matrix, precision_score, recall_score

review_threshold = 0.10
review_flag = (prob_high_risk >= review_threshold).astype(int)
tn, fp, fn, tp = confusion_matrix(y_test, review_flag).ravel()

print("进入人工复核:", int(review_flag.sum()), "人")
print("precision:", round(precision_score(y_test, review_flag, zero_division=0), 4))
print("recall:", round(recall_score(y_test, review_flag, zero_division=0), 4))
print("混淆矩阵 [[TN, FP], [FN, TP]]:")
print([[int(tn), int(fp)], [int(fn), int(tp)]])
进入人工复核: 631 人 precision: 0.0586 recall: 0.7115 混淆矩阵 [[TN, FP], [FN, TP]]: [[2354, 594], [15, 37]]
比较不同复核阈值 · Python
thresholds = [0.05, 0.10, 0.15, 0.20, 0.30]
review_counts = [(prob_high_risk >= t).sum() for t in thresholds]
recalls = [recall_score(y_test, prob_high_risk >= t) for t in thresholds]

fig, ax1 = plt.subplots(figsize=(8, 4.5))
ax1.plot(thresholds, review_counts, marker="o", color="#1f6b65")
ax1.set(xlabel="人工复核阈值", ylabel="进入复核的人数")
ax2 = ax1.twinx()
ax2.plot(thresholds, recalls, marker="s", color="#b65a2b")
ax2.set_ylabel("高风险召回率")
plt.title("阈值改变时的筛查规模与召回率")
plt.show()
不同人工复核阈值下的复核人数与高风险召回率变化图
运行上方代码后的图形输出。阈值越低,送去人工复核的人越多,高风险样本也越不容易漏掉;这是一项资源配置与消费者权益之间需要明确讨论的权衡,而不是模型替人做出的决定。
不能省略的解释

631 人中只有一小部分是课堂标签中的高风险样本,所以复核不等于拒绝;它表示需要更多信息或人工判断。降低阈值会提高召回率,也会增加复核量和误报。提高阈值会节省人工审核资源,但可能漏掉更多真实高风险样本。正确选择取决于漏筛代价、误筛代价、服务成本、风险承受能力和消费者权益,而不能只追求某一个指标。

从零写出高斯证据的核心:为什么要使用对数?

原始笔记中的 SimpleNaiveBayes 类会为每一类、每一个特征估计均值和标准差,再把各特征的概率密度相乘。许多很小的概率相乘会发生数值下溢,因此实现时先相加对数概率。GaussianNB 已经完成这些细节;理解下面函数有助于理解工具在做什么,但练习应优先使用上面的标准实现。

核心计算逻辑 · Python
import numpy as np

def gaussian_log_density(x, mean, std):
    """一个数值 x 在给定类别的高斯分布下的对数密度。"""
    std = max(std, 1e-8)
    return -0.5 * np.log(2 * np.pi * std**2) - 0.5 * ((x - mean) / std)**2

# 对每个候选类别:log(先验) + 每个特征的 log(似然)
# 比较所有类别的结果并归一化,便得到后验概率。
06

贝叶斯线性回归

传统线性回归给出一个点估计;贝叶斯线性回归给出参数分布。后者更适合需要风险区间和不确定性表达的金融决策。

朴素贝叶斯筛查主要回答“这个客户更像哪一种风险状态”,因此输出通常是不同状态的后验概率,例如低风险、高风险、进入复核。贝叶斯线性回归回答的是另一个问题:某个因素变化时,结果变量大概会怎样变化,而且这种关系有多不确定。例如数字支付活跃度提高以后,小微商户贷款额度是否更高;贷款利率上升以后,逾期概率是否也上升;某个县域的普惠金融指数提高以后,创业活跃度是否随之改善。

它的重要性在于,金融决策很多时候不能只要一个“是 / 否”标签,而要解释变量之间的关系。政策评估、额度测算、风险定价、客户分层和县域金融指标分析,都需要知道一个变量的影响方向、影响大小和不确定范围。贝叶斯回归会把系数看成不确定的量,用后验分布表达“目前证据支持什么、证据还有多强”。

和朴素贝叶斯筛查的主要区别

朴素贝叶斯筛查更像“根据证据判断状态”:看到收入、逾期记录、账户余额以后,估计客户进入复核的概率。贝叶斯线性回归更像“估计关系”:收入每增加一万元,授信额度平均变化多少;数字支付使用频率提高后,经营稳定性指标是否提高。

筛查

重点是状态判断,例如是否进入人工复核

回归

重点是变量关系,例如影响方向、大小和不确定范围

解释

不仅看预测值,还要报告可信区间和证据强弱

y=Xβ+ε,ε∼N(0,σ2I),β∼N(β0,V0)y=X\beta+\varepsilon,\quad \varepsilon\sim \mathcal N(0,\sigma^2I),\quad \beta\sim \mathcal N(\beta_0,V_0)
  • 后验均值可以理解为“数据估计”和“先验判断”的加权平均。当样本量增加时,数据的权重上升;当样本稀缺时,先验能提供稳定性。
  • 在存款利率敏感性、贷款需求预测或县域金融指标建模中,贝叶斯回归可以同时报告预测均值和可信区间,便于制定风险缓冲。
  • 常见后验形式为 p(β∣y,X)∝p(y∣X,β)p(β)p(\beta\mid y,X)\propto p(y\mid X,\beta)p(\beta)。该表达式直接说明参数估计来自似然与先验的共同作用。
怎么理解

贝叶斯回归的优势是它会告诉你“不确定到什么程度”,而不是只给一个看似精确的数字。

普惠金融例子

预测县域贷款需求时,如果样本期很短,传统回归可能给出一个点估计;贝叶斯回归可以给出可信区间,帮助银行决定是否需要更保守的额度安排。

课堂追问

在政策调整或经济下行阶段,为什么预测区间比单一预测值更重要?

07

层次贝叶斯模型

层次贝叶斯适合“多地区、多网点、多客群”的金融数据结构。它既允许群体差异,又能在样本少的群体之间共享信息。

层次贝叶斯的重要性来自一个非常现实的问题:普惠金融数据天然是分层的。客户属于某个村镇、县域、行业、支行或平台;这些群体既有共同规律,也有本地差异。如果把所有样本完全合在一起,会把偏远地区、小行业、新客户群体的特殊性抹掉;如果每个地区完全单独建模,小样本地区的估计又会非常不稳定。

层次模型提供的核心思想是“部分汇聚”:样本多的地区更多依靠本地数据,样本少的地区可以适度借用总体经验。它不是简单平均,也不是强行统一,而是在总体规律和局部差异之间建立一座桥。对数字普惠金融来说,这一点很关键,因为服务对象常常正是那些数据少、历史短、传统征信记录不足的客户群体。

和朴素贝叶斯筛查、贝叶斯线性回归的区别

朴素贝叶斯筛查关注单个客户进入某个风险状态的概率;贝叶斯线性回归关注一个总体样本中变量之间的关系;层次贝叶斯进一步承认“不同地区或群体的关系可能不一样”。因此它更适合回答:同样是数字支付活跃度,在城市商户、县域商户和农村个体户中的作用是否相同?同样的逾期记录,在不同产业周期下是否应有不同解释?

筛查

一个客户当前是否需要复核

回归

一个变量与结果之间有什么关系

层次

这种关系在不同地区或客群中是否不同

yij∼N(xij⊤βj,σ2),βj∼N(μβ,Σβ)y_{ij}\sim \mathcal N(x_{ij}^{\top}\beta_j,\sigma^2),\quad \beta_j\sim \mathcal N(\mu_{\beta},\Sigma_{\beta})
  • 下标 jj 可以表示县域、支行、行业或客户群体。每个群体有自己的参数 βj\beta_j,但这些参数又来自共同的总体分布。
  • 这种“部分池化”机制可以避免两个极端:完全合并会掩盖地区差异,完全分开会让小样本地区估计不稳定。
  • 在县域普惠金融评价中,层次模型可以把省级、县级和个体层面的信息同时纳入分析。
怎么理解

层次模型的直觉是“相似地区可以互相借力,但不能假装完全一样”。这非常适合县域和支行层面的金融数据。

普惠金融例子

一个偏远县样本很少,单独建模不稳定;完全合并到全省模型又会忽视本地产业结构。层次贝叶斯可以在两者之间取得平衡。

课堂追问

哪些变量应该在所有地区共享?哪些变量应该允许每个地区有自己的参数?

08

本章练习

  • 解释为什么“高模型准确率”并不必然意味着“高欺诈识别价值”。请结合基准概率说明。
  • 构造一个农村信贷申请人的朴素贝叶斯筛查例子,列出至少四个特征、两个风险状态和一个复核阈值。
  • 比较普通最小二乘回归和贝叶斯线性回归在风险预测报告中的表达差异。
怎么理解

练习题建议用真实业务语言回答,不要只写公式。先说明业务场景,再说明变量、假设和可能的失败点。

普惠金融例子

例如“欺诈识别”的回答可以从低欺诈率、误报成本、人工审核资源和客户体验四个角度展开。

课堂追问

如果你的模型把很多正常客户误判为高风险,对普惠金融目标有什么影响?