03 贝叶斯分类器 (Bayesian Classifiers)
90 分钟学习安排:概率 → 损失 → 决策
- 反馈: \(P(+)=0.8\times0.1+0.2\times0.9=0.26\),故 \(P(D|+)\approx0.308\),不是 0.8。
欢迎来到第三章:贝叶斯分类器
核心问题:如何在不确定性中做出最优分类?
想象你是银行的信贷经理,每天都要面对一个关键决策:
是否批准一笔贷款?
这里包含两个相连但不同的问题:先做违约状态分类,再按损失做贷款动作选择。
- 输入数据 (X): 申请人的特征,如年收入、信用记录、债务水平等。
- 真实状态 (\(Y\)):
不违约 或 违约。
- 模型输出: 后验概率 \(P(Y=\text{违约}\mid X)\)(或预测标签 \(\hat Y\))。
- 业务动作 (\(a\)):
批准 或 拒绝;动作由后验概率与损失矩阵共同决定。
案例背景:信贷审批决策
我们来看看一个简化的申请人数据。
| 001 |
15 |
720 |
否 |
? |
| 002 |
6 |
580 |
是 |
? |
| 003 |
9 |
650 |
否 |
? |
| … |
… |
… |
… |
… |
目标
先由 \(X\) 估计 \(P(Y\mid X)\),再选择使条件风险最小的动作 \(a^*(X)\);分类标签不等于审批动作。
为什么选择贝叶斯方法?
贝叶斯分类器提供了一个基于概率论的强大决策框架。
本章学习内容概览
我们将循序渐进,构建完整的贝叶斯决策体系。
第一部分:概率论基础
The Language of Uncertainty
核心概念一:先验概率 (Prior Probability)
先验概率 \(P(y=c)\) 是在获得任何新数据之前,我们对某个类别 \(c\) 出现的固有信念或历史频率。
在信贷审批的例子中,先验概率指的是:
在不查看任何申请人具体信息的情况下,根据银行历史数据,一个客户会违约的概率是多少?
它是我们决策的基准或起点。
先验概率:一个具体的例子
假设银行在过去处理了 10,000 笔贷款申请,其中 500 笔最终违约。
核心概念二:概率密度函数 (PDF)
对于连续型变量(如收入、年龄),我们使用概率密度函数 (Probability Density Function, p(x)) 来描述其分布规律。
- PDF 本身不是概率,
p(x) 的值可以大于1。
- 变量落在某个区间
[a, b] 的概率是 PDF 在该区间上的积分:\(P(a \le x \le b) = \int_a^b p(x) dx\)。
- 曲线下方的总面积为1。
PDF vs. PMF
一个重要的区分:
可视化:正态分布 (高斯分布)
正态分布是金融和商业领域最常用的PDF,它由均值 μ (中心位置) 和方差 σ² (离散程度) 决定。
核心概念三:类条件概率 (Class-Conditional)
类条件概率 \(p(x | y=c)\) 回答了这样一个问题:“如果我们已经知道样本属于类别 \(c\),那么观察到数据 \(x\) 的概率密度是多少?”
在信贷审批的例子中:
p(收入 | y = 违约): 给定一个客户是违约客户,他的收入分布是怎样的?
p(收入 | y = 不违约): 给定一个客户是优质客户,他的收入分布又是怎样的?
这是连接我们的观察 (数据 x) 和未知状态 (类别 y) 的桥梁。我们称之为似然 (Likelihood)。
可视化:不同类别客户的收入分布
假设我们从历史数据中发现,不违约客户的收入(蓝色)普遍高于违约客户(红色)。
核心概念四:后验概率 (Posterior Probability)
后验概率 \(P(y=c | x)\) 是贝叶斯决策的核心。它是在我们观察到数据 \(x\) 之后,对样本属于类别 \(c\) 的概率的更新信念。
它回答了我们最关心的问题:
“给定这位申请人的收入是12万美元,他是违约客户的概率有多大?”
这就是我们做决策的直接依据!
贝叶斯定理:从先验到后验的魔法公式
贝叶斯定理是连接这四个核心概念的数学基石。
\[
\large{P(y=c \mid \mathbf{x}) = \frac{p(\mathbf{x} \mid y=c) P(y=c)}{p(\mathbf{x})}}
\]
这个公式告诉我们如何用数据来更新我们的信念。
贝叶斯定理的直观解读
\[
\large{\underbrace{P(y=c \mid \mathbf{x})}_{\text{后验概率}} = \frac{\overbrace{p(\mathbf{x} \mid y=c)}^{\text{似然}} \times \overbrace{P(y=c)}^{\text{先验概率}}}{\underbrace{p(\mathbf{x})}_{\text{证据}}}}
\]
- 后验概率 (Posterior): 看到证据后,我们更新的信念。
- 似然 (Likelihood): 在某个类别下,看到这个证据的可能性。
- 先验概率 (Prior): 我们开始时的信念。
- 证据 (Evidence): 看到这个证据的总概率,用于归一化。
贝叶斯定理各部分可视化
“证据” p(x) 的计算:全概率公式
分母 p(x) 是观察到特定数据 x 的总概率,无论它属于哪个类别。我们使用全概率公式计算它。
第二部分:贝叶斯决策论
From Probabilities to Profits: The Art of Optimal Decision
拥有后验概率后,如何决策?
我们已经能够计算出 P(y=违约 | x) 和 P(y=不违约 | x)。
一个看似简单直观的规则是: 选择后验概率最大的那个类别。
\[
\large{f(\mathbf{x}) = \underset{c}{\arg\max} \ P(y=c \mid \mathbf{x})}
\]
这被称为最大后验概率 (MAP) 决策准则。
MAP准则的隐藏假设
MAP准则隐含了一个非常强的假设:所有类型的错误,其代价都是相同的。
在现实世界中,这个假设往往不成立。
误判的代价是不同的:引入损失函数
在信贷审批中,有两种错误:
- 第一类错误 (False Negative): 把违约客户误判为“不违约” (批准了坏账贷款)。
- 第二类错误 (False Positive): 把不违约客户误判为“违约” (拒绝了优质客户)。
量化代价:损失矩阵 L(a, y)
我们用损失矩阵 L(a, y)量化“真实状态为 \(y\) 时采取动作 \(a\)”的代价。
期望损失:衡量决策的长期平均成本
对于观测 \(x\),若采取动作 \(a\),其期望损失 (Expected Loss) 或 条件风险 (Conditional Risk) \(R(a|x)\) 是所有真实状态 \(y\) 的损失加权平均,权重为后验概率。
\[
\large{R(a \mid \mathbf{x}) = \sum_{y} L(a, y) P(Y=y \mid \mathbf{x})}
\]
这个公式计算的是:“如果我采取动作 \(a\),平均要承担多大损失?”
期望损失计算:一步步来
假设对于某个申请人 x,我们算出的后验概率是:
P(y=不违约 | x) = 0.8
P(y=违约 | x) = 0.2
再回顾我们的损失矩阵 (简化为数值):
- L(批准, 不违约) = -2 (赚2万)
- L(批准, 违约) = 50 (亏50万)
- L(拒绝, 不违约) = 0.1 (机会成本0.1万)
- L(拒绝, 违约) = 0
计算 R(批准 | x)
如果我们选择“批准”这笔贷款:
R(批准 | x) = L(批准, 不违约) * P(不违约|x) + L(批准, 违约) * P(违约|x)
\[
\large{R(\text{批准} \mid \mathbf{x}) = (-2) \times 0.8 + (50) \times 0.2 = -1.6 + 10 = 8.4}
\]
选择“批准”的期望损失是 8.4万元。
计算 R(拒绝 | x)
如果我们选择“拒绝”这笔贷款:
R(拒绝 | x) = L(拒绝, 不违约) * P(不违约|x) + L(拒绝, 违约) * P(违约|x)
\[
\large{R(\text{拒绝} \mid \mathbf{x}) = (0.1) \times 0.8 + (0) \times 0.2 = 0.08}
\]
选择“拒绝”的期望损失是 0.08万元。
贝叶斯决策准则:选择期望损失最小的决策
最优动作 \(a^*(x)\) 是对每一个 \(x\),选择使条件风险 \(R(a|x)\) 最小的动作。
\[
\large{a^*(\mathbf{x}) = \underset{a}{\arg\min} \ R(a \mid \mathbf{x})}
\]
在我们的例子中: R(批准|x) = 8.4 vs R(拒绝|x) = 0.08。 因为 0.08 < 8.4,所以最优决策是“拒绝”。
尽管该申请人有80%的概率是不违约的优质客户!但20%的违约风险和高昂的损失使得拒绝成为更理性的选择。
一个特例:0-1 损失函数
如果所有误判的代价都相等(设为1),正确分类的代价为0,这就是 0-1 损失函数。
\[
\large{L(i, j) =
\begin{cases}
0, & \text{if } i = j \\
1, & \text{if } i \neq j
\end{cases}}
\]
0-1 损失下的决策规则
在 0-1 损失下,期望损失 R(i|x) 变为:
\[
\large{R(i \mid \mathbf{x}) = \sum_{j=1}^{C} L(i, j) P(y=j \mid \mathbf{x}) = \sum_{j \neq i} P(y=j \mid \mathbf{x})}
\]
\[
\large{= 1 - P(y=i \mid \mathbf{x})}
\]
最小化 R(i|x) 就等价于最小化 1 - P(y=i|x),也就是最大化后验概率 P(y=i|x)。
因此,MAP决策准则是最小化期望损失在0-1损失函数下的一个特例。
可视化:决策边界
对于MAP准则,决策边界就是后验概率相等的地方,例如 P(y=1|x) = P(y=2|x)。
第三部分:参数估计
Learning from Data: The Estimation Challenge
现实挑战:我们并不知道真实的概率分布
到目前为止,我们都假设 P(y=c) 和 p(x|y=c) 是已知的。
但在现实中,我们无法预知它们。我们拥有的只是一堆历史数据 (训练集)。
核心任务
如何从数据中估计出这些概率分布的参数?
参数估计的思路
- 选择模型: 我们先假设数据服从某种特定形式的概率分布,例如高斯分布 \(\mathcal{N}(\mu, \sigma^2)\)。
- 估计参数: 我们的任务就变成了从数据中估计出这个模型的未知参数 \(\theta = (\mu, \sigma^2)\)。
方法一:极大似然估计 (MLE)
极大似然估计 (Maximum Likelihood Estimation, MLE) 的核心思想是:
选择一组参数 \(θ\),使得我们观测到的这组数据 \(X = {x_1, ..., x_N}\) 出现的联合概率最大。
换句话说,哪组参数对我们手头数据的“解释”最好?
似然函数 L(θ|X)
我们定义似然函数 L(θ|X),它表示在参数 θ 下,观测到数据 X 的概率。
假设样本是独立同分布的(i.i.d.),联合概率就是每个样本概率的乘积:
\[
\large{L(\theta \mid X) = p(X \mid \theta) = \prod_{n=1}^{N} p(x_n \mid \theta)}
\]
我们的目标是找到使 L(θ|X) 最大的 θ*。
\[
\large{\theta^*_{MLE} = \underset{\theta}{\arg\max} \ L(\theta \mid X)}
\]
MLE的技巧:使用对数似然函数
由于连乘积的计算和求导都非常复杂,我们通常最大化对数似然函数 LL(θ|X)。
因为对数函数是单调递增的,最大化 L 和最大化 log(L) 的结果是相同的。
\[
\large{LL(\theta \mid X) = \log p(X \mid \theta) = \sum_{n=1}^{N} \log p(x_n \mid \theta)}
\]
这样,连乘就变成了求和,大大简化了计算。
MLE示例:估计正态分布的均值
假设我们的数据 \(x_1, ..., x_N\) 来自一个方差 \(σ²\) 已知,但均值 \(μ\) 未知的正态分布。
对数似然函数为:
\[
\large{LL(\mu) = \sum_{n=1}^{N} \log \left( \frac{1}{\sqrt{2\pi\sigma^2}} e^{-\frac{(x_n - \mu)^2}{2\sigma^2}} \right)}
\]
对 \(μ\) 求导并令其为0,我们可以解出:
\[
\large{\hat{\mu}_{MLE} = \frac{1}{N} \sum_{n=1}^{N} x_n}
\]
结果非常直观:样本均值就是对总体均值的极大似然估计。
MLE的局限性:过拟合
MLE完全“相信”数据。如果数据量很小或有偏差,MLE的结果可能很差。
经典例子:抛硬币。
- 你抛了3次硬币,结果都是正面。
- MLE会估计正面的概率 \(p(H) = 3/3 = 1\)。
- 这意味着你将永远不会预测出反面。这显然是不合理的。
我们需要一种方法来融入我们对世界的先验知识(比如,硬币通常是公平的)。
方法二:最大后验概率估计 (MAP)
MAP (Maximum a Posteriori) 估计在MLE的基础上,引入了对参数 θ 本身的先验分布 p(θ)。
它不再是最大化似然 p(X|θ),而是最大化参数的后验概率 p(θ|X)。
\[
\large{p(\theta \mid X) \propto p(X \mid \theta) p(\theta)}
\]
MAP的目标是:
\[
\large{\theta^*_{MAP} = \underset{\theta}{\arg\max} \ [p(X \mid \theta) p(\theta)]}
\]
MAP的对数形式
同样使用对数可以简化计算:
\[
\large{\theta^*_{MAP} = \underset{\theta}{\arg\max} \ [\log p(X \mid \theta) + \log p(\theta)]}
\]
\[
\large{= \underset{\theta}{\arg\max} \left[ \sum_{n=1}^{N} \log p(x_n \mid \theta) + \log p(\theta) \right]}
\]
MAP:数据证据与先验信念的平衡
\[
\large{\underbrace{\log p(\theta\mid X)}_{\text{对数后验}} = \underbrace{\sum_n \log p(x_n\mid\theta)}_{\text{对数似然}} + \underbrace{\log p(\theta)}_{\text{对数先验}} + \text{constant}}
\]
第四部分:处理复杂分布
When Reality is Messy: Mixture Models
单一模型的局限性
到目前为止,我们都假设一个类别的数据可以用一个简单的分布(如单个高斯分布)来描述。但如果数据分布更复杂呢?
核心内容提示:GMM/EM 为拓展内容;核心内容从 MLE/MAP 直接进入朴素贝叶斯。
复杂情况:高斯混合模型 (GMM)
拓展内容提示:核心内容从 MLE/MAP 直接进入朴素贝叶斯的高维挑战;GMM/EM 完成主要练习与总结后再返回选讲。
如果我们的数据分布是由多个“集群”混合而成呢?
例如,客户的消费行为可能分为“高消费”、“中等消费”和“低消费”三个群体,每个群体内部都近似正态分布。
高斯混合模型 (Gaussian Mixture Model, GMM) 正是为此而生。
GMM的定义:多个高斯的加权和
GMM 将一个复杂的概率分布建模为 K 个高斯分量的加权和。
\[
\large{p(\mathbf{x}) = \sum_{k=1}^{K} \pi_k \mathcal{N}(\mathbf{x} \mid \mu_k, \Sigma_k)}
\]
其中:
- \(K\): 混合分量的数量 (超参数)。
- \(π_k\): 第 \(k\) 个分量的混合系数 (权重),且 \(\sum_{k=1}^{K} \pi_k = 1\)。
- \(μ_k, Σ_k\): 第 \(k\) 个高斯分量的均值和协方差矩阵。
GMM的挑战:隐变量问题
GMM的参数估计(\(π_k, μ_k, Σ_k\))比单个高斯要复杂得多。
因为我们不知道每个数据点 \(x_n\) 究竟属于哪个高斯分量。这个“归属”信息是一个隐变量 (latent variable)。
这是一个“鸡生蛋,蛋生鸡”的问题:
- 如果知道了每个点属于哪个集群,我们就可以轻松估计每个集群的参数。
- 如果知道了每个集群的参数,我们就可以计算每个点属于哪个集群的概率。
解决方法:期望最大化算法 (EM)
期望最大化 (Expectation-Maximization, EM) 算法 是一种迭代算法,专门用来解决含有隐变量的参数估计问题。
它优雅地解决了“鸡生蛋,蛋生鸡”的困境,通过交替执行两个步骤直到收敛。
EM算法:E-步 (Expectation)
E-步 (期望)
基于当前的模型参数,计算每个数据点 \(x_n\) 由每个高斯分量 \(k\) 生成的后验概率(也叫“责任” \(r_{nk}\))。
\[
\large{r_{nk} = P(z_n=k \mid x_n; \theta_{old})}
\]
通俗地说,就是对每个数据点进行“软分配”,猜测它有多大可能性来自每个集群。
EM算法:M-步 (Maximization)
M-步 (最大化)
基于 E-步计算出的“责任” \(r_nk\),更新模型参数 \(π_k, μ_k, Σ_k\),以最大化期望对数似然。
这相当于对每个集群进行加权的MLE估计,权重就是 \(r_nk\)。
例如,新的均值是所有数据点的加权平均:
\[
\large{\mu_k^{new} = \frac{\sum_{n=1}^N r_{nk} x_n}{\sum_{n=1}^N r_{nk}}}
\]
EM算法流程
拓展内容结束:结束 GMM/EM 后,进入最终总结,不重放已经完成的 核心内容。
第五部分:朴素贝叶斯分类器
Putting it all Together: The Naive Bayes Classifier
挑战:高维数据的诅咒
当我们的数据 x 有多个特征时,直接估计 d 维的联合概率分布 p(x|y=c) 非常困难,需要海量数据,这就是所谓的“维度灾难”。
“朴素”的假设:特征条件独立性
朴素贝叶斯 (Naïve Bayes) 分类器做了一个非常大胆(但常常有效)的简化假设:
给定类别 \(y\),所有特征 \(x_i\) 之间是相互独立的。
这意味着:知道了客户是“违约”客户后,他的“收入”高低和他的“年龄”大小是两个独立的信息。
独立性假设的威力
这个“朴素”的假设让联合概率的计算变得异常简单:
原本复杂的联合概率:
\[ \large{p(\mathbf{x}|y=c) = p(x_1, x_2, \ldots, x_d | y=c)} \]
在独立性假设下,可以分解为各个特征的类条件概率的乘积:
\[ \large{p(\mathbf{x}|y=c) = \prod_{i=1}^{d} p(x_i | y=c)} \]
现在我们只需要为每个特征单独估计一维的 \(p(x_i|y=c)\),这比估计高维联合分布容易得多!
朴素贝叶斯的图模型
这个假设可以用一个简单的图模型来表示。
另一个现实问题:零概率
考虑一个文本分类任务(如垃圾邮件检测),特征是离散的词汇。
我们用 MLE 估计类条件概率 p(单词="offer" | 类别="垃圾邮件"),即计算训练集中垃圾邮件里 “offer” 出现的频率。
问题
如果在训练集的垃圾邮件中,“wanli” 这个词从未出现过,那么:
\[
\large{p(\text{单词}="\text{wanli}" \mid y=\text{垃圾邮件}) = 0}
\]
零概率的致命后果
如果 p("wanli" | 垃圾邮件) = 0,那么对于任何包含 “wanli” 的新邮件,其被分类为垃圾邮件的后验概率将直接变为0!
\[
\large{P(\text{垃圾} \mid \text{邮件}) \propto \ldots \times \overbrace{p(\text{"wanli"} \mid \text{垃圾})}^{=0} \times \ldots = 0}
\]
仅仅因为一个词在训练集中没见过,就完全排除了一个类别的可能性,这是非常脆弱和不合理的。模型“见过”的太少,太绝对了。
解决方案:拉普拉斯平滑 (Laplace Smoothing)
拉普拉斯平滑,也叫加法平滑 (Additive Smoothing),是一种简单而有效的处理零概率问题的方法。
它的核心思想是:在计算概率时,为所有可能事件的计数都人为地加上一个小常数 λ (通常为1)。
这相当于给每个可能出现的事件一个“基础票”,保证即使某个事件在样本中从未出现,其估计出的概率也不会是零。
拉普拉斯平滑的公式
对于离散特征,没有平滑的MLE估计是:
\[
\large{P(x_i = v \mid y=c) = \frac{N_{cv}}{N_c}}
\]
- \(N_cv\): 类别c中特征值为v的样本数
- \(N_c\): 类别c的总样本数
加入拉普拉斯平滑(λ > 0)后:
\[
\large{P_{\lambda}(x_i = v \mid y=c) = \frac{N_{cv} + \lambda}{N_c + \lambda S_i}}
\]
- \(S_i\): 特征 \(i\) 可能取值的总数量(如词汇表大小)
- \(λ\): 平滑参数(\(λ=1\) 时称为“加一平滑”)
平滑效果:一个例子
假设一个特征有两个取值 {Yes, No},在类别 c 下有10个样本。
- 观察到 10 次 ‘Yes’,0 次 ‘No’。
- \(S_i = 2\) (两个可能取值)
MLE 估计:
P('Yes'|c) = 10/10 = 1
P('No'|c) = 0/10 = 0 (危险!)
拉普拉斯平滑 (λ=1):
P('Yes'|c) = (10+1)/(10+1*2) = 11/12 ≈ 0.917
P('No'|c) = (0+1)/(10+1*2) = 1/12 ≈ 0.083 (问题解决!)
进入主要案例前的学习目标回顾
回顾开场目标:①由先验、似然计算后验;②用损失矩阵而非最大概率作决策;③区分 MLE 与 MAP;④检验朴素条件独立假设并评价概率预测。
- 回顾题: 已知 \(P(D)=0.1\)、\(P(+|D)=0.8\)、\(P(+|\neg D)=0.2\),先算 \(P(+)\)。
- 答案: \(P(+)=0.8\times0.1+0.2\times0.9=0.26\);因此 \(P(D|+)=0.08/0.26\approx0.308\),不是 0.8。
形成性检查 1:概率还是决策?
客户违约后验概率为 0.30;“批准后违约”损失为 10,“拒绝但不违约”损失为 1。应批准还是拒绝?
答案
批准风险 \(0.30\times10=3\);拒绝风险 \(0.70\times1=0.7\),故拒绝。最大后验类别与最小期望损失决策不必一致。
主要案例:福耀玻璃高斯朴素贝叶斯
本例数据: data/stock/stock_price_pre_adjusted.h5;key=data;福耀玻璃 600660.XSHG;2018–2024;close、volume;用 \(t\) 时点收益、绝对收益与成交量增速预测 \(t+1\) 是否下跌;前 80% 训练、后 20% 测试。
邻近方法来源: scikit-learn GaussianNB 文档;本例同时报告阈值判断与概率排序证据。
Code
from pathlib import Path # 使用统一路径对象定位数据文件
import pandas as pd # 导入表格工具以读取本地行情
from sklearn.naive_bayes import GaussianNB # 使用高斯朴素贝叶斯估计类条件密度
from sklearn.metrics import balanced_accuracy_score, roc_auc_score # 同时评价类别判断与概率排序
# 公网下载:https://assets.qiufei.site/data/stock/stock_price_pre_adjusted.h5
# 下载后把下一行改为本机文件位置;按课程结构存放时可用 Path("data/stock/stock_price_pre_adjusted.h5")。
# Windows:Path(r"C:\qiufei\data\stock\stock_price_pre_adjusted.h5")
# macOS:Path("/Users/你的用户名/data/stock/stock_price_pre_adjusted.h5")
# Linux:Path("/home/你的用户名/data/stock/stock_price_pre_adjusted.h5")
price_path = Path("/home/ubuntu/r2_data_mount/data/stock/stock_price_pre_adjusted.h5")
price_rows = pd.read_hdf(price_path, key='data', where=['order_book_id=="600660.XSHG"', 'date>=Timestamp("2018-01-01")', 'date<=Timestamp("2024-12-31")'], columns=['close', 'volume']) # 只载入目标公司、时期和字段
bayes_frame = price_rows.reset_index().sort_values('date') # 按预测可用时间排序
bayes_frame['return_t'] = bayes_frame['close'].pct_change() # 构造当日收益率特征
bayes_frame['abs_return_t'] = bayes_frame['return_t'].abs() # 用绝对收益代理当日波动冲击
bayes_frame['volume_growth_t'] = bayes_frame['volume'].pct_change() # 构造成交量增速特征
bayes_frame['future_return_t1'] = bayes_frame['return_t'].shift(-1) # 先保留连续未来收益,避免把未知末日静默编码为零
bayes_frame['target_date_t1'] = bayes_frame['date'].shift(-1) # 保存标签实现日以清除跨窗口样本
bayes_frame = bayes_frame.replace([float('inf'), float('-inf')], pd.NA).dropna() # 在标签转整数前删除所有不可观测或非有限记录
Code
bayes_frame['down_t1'] = (bayes_frame['future_return_t1'] < 0).astype(int) # 仅对已观测未来收益构造二元标签
assert bayes_frame['future_return_t1'].notna().all() and bayes_frame['date'].max() < price_rows.reset_index()['date'].max() # 确认每个特征日都对应更晚的真实标签实现日
split_row = int(len(bayes_frame) * 0.8) # 事先确定时间切分位置
test_start_date = bayes_frame.iloc[split_row]['date'] # 从完整序列确定测试起点
train_rows = bayes_frame[(bayes_frame['date'] < test_start_date) & (bayes_frame['target_date_t1'] < test_start_date)] # 清除到测试期才实现的训练标签
test_rows = bayes_frame[bayes_frame['date'] >= test_start_date] # 确定测试特征窗口
assert train_rows['target_date_t1'].max() < test_rows['date'].min() # 确认标签实现边界
feature_names = ['return_t', 'abs_return_t', 'volume_growth_t'] # 声明模型实际使用的语义字段
bayes_model = GaussianNB().fit(train_rows[feature_names], train_rows['down_t1']) # 在训练期估计先验和类条件分布
down_probability = bayes_model.predict_proba(test_rows[feature_names])[:, 1] # 输出测试期下跌后验概率
pd.Series({'balanced_accuracy': balanced_accuracy_score(test_rows['down_t1'], down_probability >= 0.5), 'roc_auc': roc_auc_score(test_rows['down_t1'], down_probability), 'test_rows': len(test_rows)}) # 报告样本外指标与样本数
balanced_accuracy 0.486806
roc_auc 0.448681
test_rows 340.000000
dtype: float64
形成性检查 2:朴素假设
return_t 与 abs_return_t 显然相关,朴素贝叶斯还能运行吗?输出能否直接当因果效应?
答案
能运行,但条件独立假设失配可能导致概率校准较差;应检查校准曲线并与基准比较。后验是观测预测,不是干预效应。
分步练习:损失敏感阈值
- 任务: 假设漏报下跌损失为误报的 4 倍,推导最优概率阈值并重新报告混淆矩阵。
Code
from sklearn.metrics import confusion_matrix, precision_score, recall_score # 计算成本阈值下的可核对分类结果
threshold_rows = [] # 收集两个阈值的完整比较
for probability_threshold in [0.5, 0.2]: # 对照默认阈值与四比一成本阈值
threshold_prediction = down_probability >= probability_threshold # 将同一测试概率转为类别决策
threshold_matrix = confusion_matrix(test_rows['down_t1'], threshold_prediction) # 固定标签顺序得到 TN、FP、FN、TP
threshold_rows.append({'threshold': probability_threshold, 'precision': precision_score(test_rows['down_t1'], threshold_prediction), 'recall': recall_score(test_rows['down_t1'], threshold_prediction), 'tn': threshold_matrix[0, 0], 'fp': threshold_matrix[0, 1], 'fn': threshold_matrix[1, 0], 'tp': threshold_matrix[1, 1]}) # 保存指标与四格计数
pd.DataFrame(threshold_rows) # 展示阈值降低后的召回—精确率权衡
综合练习
将对象改为恒瑞医药 600276.XSHG,用 2023–2024 作为固定测试期;比较 GaussianNB 与只使用类别先验的基准,并绘制 5 组概率分箱校准表。
综合练习完整答案:基准与五组校准
Code
transfer_features = ['return_t', 'return_5d_t', 'volatility_5d_t', 'volume_growth_t'] # 固定四个 t 时点可得特征
transfer_bayes = GaussianNB().fit(transfer_train[transfer_features], transfer_train['down_t1']) # 只在训练期拟合模型
transfer_probability = transfer_bayes.predict_proba(transfer_test[transfer_features])[:, 1] # 对测试期生成下跌概率
prior_probability = pd.Series(transfer_train['down_t1'].mean(), index=transfer_test.index) # 构造只含训练期类别先验的基准
transfer_metrics = pd.DataFrame({'model': ['GaussianNB', 'class-prior baseline'], 'roc_auc': [roc_auc_score(transfer_test['down_t1'], transfer_probability), roc_auc_score(transfer_test['down_t1'], prior_probability)], 'balanced_accuracy': [balanced_accuracy_score(transfer_test['down_t1'], transfer_probability >= 0.5), balanced_accuracy_score(transfer_test['down_t1'], prior_probability >= 0.5)]}) # 汇总同一测试期指标
calibration_frame = pd.DataFrame({'observed': transfer_test['down_t1'].to_numpy(), 'probability': transfer_probability}) # 对齐概率与真实结果
calibration_frame['probability_bin'] = pd.cut(calibration_frame['probability'], bins=[0, .2, .4, .6, .8, 1], include_lowest=True) # 按预先声明边界划分五组
calibration_table = calibration_frame.groupby('probability_bin', observed=False).agg(n=('observed', 'size'), mean_probability=('probability', 'mean'), observed_rate=('observed', 'mean')).reset_index() # 计算每组预测均值与真实频率
display(transfer_metrics) # 输出模型与先验基准的关键指标
calibration_table # 输出完整五组校准表
形成性检查 3:MLE 与 MAP
样本很少且先验集中时,MLE 与 MAP 哪个更容易被先验收缩?样本量增大后差异如何?
答案
MAP 直接加入先验,因而小样本时更受收缩;在常规正则条件下,样本量增大后似然占主导,两者通常接近。
来源与延伸阅读
- Berger, Statistical Decision Theory and Bayesian Analysis。
- Murphy, Probabilistic Machine Learning: An Introduction, classification chapters。
- McCallum & Nigam (1998), naive Bayes event models。
- 数据:本地 A 股前复权行情数据;字段与筛选如 前面的案例 所列。
本章总结:贝叶斯分类器的核心思想
课后选学:完成核心内容后,可以继续学习GMM/EM,随后进入最终总结。
课程预告
今天我们深入探讨了生成式模型 (Generative Models) 的一种经典方法——贝叶斯分类器。
我们学习了如何对 p(x|y) 和 P(y) 进行建模。
接下来,我们将学习另一大类模型:判别式模型 (Discriminative Models),例如逻辑回归。这类模型将跳过对 p(x|y) 的建模,直接对后验概率 P(y|x) 进行建模。