概率与常见分布
概率论是机器学习的第三根支柱(线性代数、微积分、概率论)。贝叶斯公式 P(A|B)=P(B|A)P(A)/P(B) 是垃圾邮件过滤(朴素贝叶斯)、医学诊断、贝叶斯神经网络的数学基础;高斯分布是噪声建模的默认假设——MSE 损失等价于假设数据服从高斯分布的 MLE,VAE 的隐空间先验也是标准正态 N(0,I);伯努利/二项分布对应二分类的 BCE 损失;多项分布/Categorical 分布对应 Softmax + 交叉熵;多维高斯的协方差矩阵刻画特征间关联,高斯混合模型(GMM)用于聚类和密度估计;KL 散度 DKL(P‖Q) 衡量两个分布的差异——VAE 的 ELBO 目标函数、知识蒸馏(teacher→student)、RLHF 中的 KL 惩罚项都直接使用 KL 散度。本节系统讲解每种分布的定义、公式、数值计算、参数含义以及它在实际 AI 模型中的具体角色。
一、概率的基本概念
概率公理(柯尔莫哥洛夫):
① 0 ≤ P(A) ≤ 1(概率在 0 到 1 之间)
② P(Ω) = 1(必然事件概率为 1)
③ 互斥事件的概率可加:P(A∪B) = P(A) + P(B)(若 A∩B=∅)
条件概率:P(A|B) = P(A∩B) / P(B)
含义:已知 B 发生的前提下,A 发生的概率
贝叶斯公式:P(A|B) = P(B|A) × P(A) / P(B)
含义:通过观测到的证据 B,更新对假设 A 的信念
① 0 ≤ P(A) ≤ 1(概率在 0 到 1 之间)
② P(Ω) = 1(必然事件概率为 1)
③ 互斥事件的概率可加:P(A∪B) = P(A) + P(B)(若 A∩B=∅)
条件概率:P(A|B) = P(A∩B) / P(B)
含义:已知 B 发生的前提下,A 发生的概率
贝叶斯公式:P(A|B) = P(B|A) × P(A) / P(B)
含义:通过观测到的证据 B,更新对假设 A 的信念
贝叶斯公式的现实应用——医疗检测:
某疾病在人群中的患病率:P(病) = 0.001(千分之一)
检测灵敏度(真阳性率):P(阳性|病) = 0.99
特异度(真阴性率):P(阴性|健康) = 0.95 → P(阳性|健康) = 0.05(假阳性率 5%)
问题:检测结果阳性,实际患病的概率是多少?
P(阳性) = P(阳性|病)P(病) + P(阳性|健康)P(健康)
= 0.99×0.001 + 0.05×0.999
= 0.00099 + 0.04995 = 0.05094
P(病|阳性) = P(阳性|病)P(病) / P(阳性)
= 0.00099 / 0.05094 = 0.0194 = 1.94%
令人惊讶的结论:即使检测结果为阳性,实际患病概率只有 1.94%!
原因:基础患病率太低(0.1%),假阳性的人数(0.05×999)远多于真阳性的人数(0.99×1)。
AI 中的类比:在极度不平衡的分类任务(如欺诈检测:0.1% 欺诈率)中,模型即使精度 95%,阳性预测中也会有大量假阳性。
某疾病在人群中的患病率:P(病) = 0.001(千分之一)
检测灵敏度(真阳性率):P(阳性|病) = 0.99
特异度(真阴性率):P(阴性|健康) = 0.95 → P(阳性|健康) = 0.05(假阳性率 5%)
问题:检测结果阳性,实际患病的概率是多少?
P(阳性) = P(阳性|病)P(病) + P(阳性|健康)P(健康)
= 0.99×0.001 + 0.05×0.999
= 0.00099 + 0.04995 = 0.05094
P(病|阳性) = P(阳性|病)P(病) / P(阳性)
= 0.00099 / 0.05094 = 0.0194 = 1.94%
令人惊讶的结论:即使检测结果为阳性,实际患病概率只有 1.94%!
原因:基础患病率太低(0.1%),假阳性的人数(0.05×999)远多于真阳性的人数(0.99×1)。
AI 中的类比:在极度不平衡的分类任务(如欺诈检测:0.1% 欺诈率)中,模型即使精度 95%,阳性预测中也会有大量假阳性。
二、离散分布
2.1 伯努利分布 Bernoulli(p)
只有两个结果:成功(X=1)概率 p,失败(X=0)概率 1-p
P(X=k) = pᵏ(1-p)¹⁻ᵏ,k ∈ {0, 1}
期望 E[X] = p,方差 Var(X) = p(1-p)
P(X=k) = pᵏ(1-p)¹⁻ᵏ,k ∈ {0, 1}
期望 E[X] = p,方差 Var(X) = p(1-p)
AI 应用:二分类输出。Sigmoid 输出 σ(z) = 0.73 表示 P(Y=1|x) = 0.73。
一个样本的二元交叉熵损失就是对伯努利分布求负对数似然:
L = -[y·ln(p) + (1-y)·ln(1-p)]
一个样本的二元交叉熵损失就是对伯努利分布求负对数似然:
L = -[y·ln(p) + (1-y)·ln(1-p)]
2.2 分类分布 / 多项式分布 Categorical(p₁,...,pₖ)
K 个类别,每个类别概率 pᵢ,Σpᵢ = 1
P(X=k) = pₖ
P(X=k) = pₖ
CIFAR-10 图像分类(10 个类别):
Softmax 输出的概率向量就是一个分类分布:
P = [0.02, 0.01, 0.05, 0.70, 0.03, 0.02, 0.01, 0.10, 0.04, 0.02]
飞机 汽车 鸟 猫 鹿 狗 蛙 马 船 卡车
这是 Categorical(0.02, 0.01, ..., 0.02) 分布。
按此分布采样:大约 70% 概率采样到 "猫"。
多分类交叉熵 = 负对数似然:L = -ln(p_true) = -ln(0.70) = 0.357
如果真实标签是猫,损失 0.357。
Softmax 输出的概率向量就是一个分类分布:
P = [0.02, 0.01, 0.05, 0.70, 0.03, 0.02, 0.01, 0.10, 0.04, 0.02]
飞机 汽车 鸟 猫 鹿 狗 蛙 马 船 卡车
这是 Categorical(0.02, 0.01, ..., 0.02) 分布。
按此分布采样:大约 70% 概率采样到 "猫"。
多分类交叉熵 = 负对数似然:L = -ln(p_true) = -ln(0.70) = 0.357
如果真实标签是猫,损失 0.357。
2.3 二项分布 Binomial(n, p)
n 次独立伯努利试验中成功 k 次的概率:
P(X=k) = C(n,k) × pᵏ × (1-p)ⁿ⁻ᵏ
E[X] = np,Var(X) = np(1-p)
P(X=k) = C(n,k) × pᵏ × (1-p)ⁿ⁻ᵏ
E[X] = np,Var(X) = np(1-p)
模型预测准确率的抽样检验:
模型声称准确率 p=0.92,随机抽 20 个样本检验。
预测恰好 18 个正确的概率:
P(X=18) = C(20,18) × 0.92¹⁸ × 0.08²
= 190 × 0.2285 × 0.0064
= 190 × 0.001462 = 0.278 = 27.8%
预测 ≥18 个正确的概率:
P(X≥18) = P(18) + P(19) + P(20)
P(19) = 20 × 0.92¹⁹ × 0.08¹ = 20 × 0.2102 × 0.08 = 0.336
P(20) = 0.92²⁰ = 0.189
P(X≥18) = 0.278 + 0.336 + 0.189 = 0.803 = 80.3%
期望正确数 = 20 × 0.92 = 18.4
模型声称准确率 p=0.92,随机抽 20 个样本检验。
预测恰好 18 个正确的概率:
P(X=18) = C(20,18) × 0.92¹⁸ × 0.08²
= 190 × 0.2285 × 0.0064
= 190 × 0.001462 = 0.278 = 27.8%
预测 ≥18 个正确的概率:
P(X≥18) = P(18) + P(19) + P(20)
P(19) = 20 × 0.92¹⁹ × 0.08¹ = 20 × 0.2102 × 0.08 = 0.336
P(20) = 0.92²⁰ = 0.189
P(X≥18) = 0.278 + 0.336 + 0.189 = 0.803 = 80.3%
期望正确数 = 20 × 0.92 = 18.4
三、连续分布
3.1 均匀分布 Uniform(a, b)
p(x) = 1/(b-a),a ≤ x ≤ b
E[X] = (a+b)/2,Var(X) = (b-a)²/12
E[X] = (a+b)/2,Var(X) = (b-a)²/12
AI 应用:随机裁剪、Dropout mask 生成。
Dropout(p=0.5):对每个神经元生成 U(0,1) 的随机数 r。若 r < 0.5 则关闭该神经元。
例:r = [0.23, 0.81, 0.45, 0.67, 0.12],阈值 0.5
→ mask = [0, 1, 0, 1, 0](关闭第 1,3,5 个神经元)
Dropout(p=0.5):对每个神经元生成 U(0,1) 的随机数 r。若 r < 0.5 则关闭该神经元。
例:r = [0.23, 0.81, 0.45, 0.67, 0.12],阈值 0.5
→ mask = [0, 1, 0, 1, 0](关闭第 1,3,5 个神经元)
3.2 高斯分布(正态分布)N(μ, σ²) —— AI 中最重要的分布
p(x) = (1/(σ√(2π))) × exp(-(x-μ)²/(2σ²))
μ = 均值(钟形曲线的中心位置)
σ = 标准差(钟形曲线的宽窄程度)
σ² = 方差
68-95-99.7 法则:
P(μ-σ < X < μ+σ) = 68.27%
P(μ-2σ < X < μ+2σ) = 95.45%
P(μ-3σ < X < μ+3σ) = 99.73%
μ = 均值(钟形曲线的中心位置)
σ = 标准差(钟形曲线的宽窄程度)
σ² = 方差
68-95-99.7 法则:
P(μ-σ < X < μ+σ) = 68.27%
P(μ-2σ < X < μ+2σ) = 95.45%
P(μ-3σ < X < μ+3σ) = 99.73%
数值示例:成年男性身高 ~ N(170, 6²)
μ=170cm, σ=6cm
问:身高 180cm 的概率密度?
p(180) = (1/(6×2.507)) × exp(-(180-170)²/(2×36))
= (1/15.04) × exp(-100/72)
= 0.0665 × exp(-1.389)
= 0.0665 × 0.2494 = 0.0166
问:身高在 164~176(μ±σ)的概率?
= 68.27%(约三分之二的人在这个范围内)
问:身高超过 182cm(μ+2σ)的概率?
= (1-95.45%)/2 = 2.275%(约 44 人中有 1 人)
问:身高超过 188cm(μ+3σ)的概率?
= (1-99.73%)/2 = 0.135%(约 740 人中有 1 人)
μ=170cm, σ=6cm
问:身高 180cm 的概率密度?
p(180) = (1/(6×2.507)) × exp(-(180-170)²/(2×36))
= (1/15.04) × exp(-100/72)
= 0.0665 × exp(-1.389)
= 0.0665 × 0.2494 = 0.0166
问:身高在 164~176(μ±σ)的概率?
= 68.27%(约三分之二的人在这个范围内)
问:身高超过 182cm(μ+2σ)的概率?
= (1-95.45%)/2 = 2.275%(约 44 人中有 1 人)
问:身高超过 188cm(μ+3σ)的概率?
= (1-99.73%)/2 = 0.135%(约 740 人中有 1 人)
高斯分布在 AI 中的 7 大应用:
① 权重初始化:He 初始化 w ~ N(0, 2/n_in)
784 个输入的层:w ~ N(0, 2/784) = N(0, 0.00255),σ=0.0505
② 噪声注入:数据增强时给输入加 N(0, 0.01) 噪声
③ BatchNorm:将每层激活值标准化为 ≈ N(0, 1)
④ VAE 隐变量:假设潜在空间 z ~ N(0, I),KL 散度迫使编码器输出接近此先验
⑤ 扩散模型(Stable Diffusion):从纯高斯噪声 N(0, I) 逐步去噪生成图片
⑥ 高斯过程回归:函数值的先验分布是多维高斯
⑦ 概率预测:回归任务输出 μ 和 σ,而非单个值
① 权重初始化:He 初始化 w ~ N(0, 2/n_in)
784 个输入的层:w ~ N(0, 2/784) = N(0, 0.00255),σ=0.0505
② 噪声注入:数据增强时给输入加 N(0, 0.01) 噪声
③ BatchNorm:将每层激活值标准化为 ≈ N(0, 1)
④ VAE 隐变量:假设潜在空间 z ~ N(0, I),KL 散度迫使编码器输出接近此先验
⑤ 扩散模型(Stable Diffusion):从纯高斯噪声 N(0, I) 逐步去噪生成图片
⑥ 高斯过程回归:函数值的先验分布是多维高斯
⑦ 概率预测:回归任务输出 μ 和 σ,而非单个值
3.3 多维高斯分布 N(μ, Σ)
p(x) = (1/√((2π)ⁿ|Σ|)) × exp(-½(x-μ)ᵀΣ⁻¹(x-μ))
μ: n 维均值向量
Σ: n×n 协方差矩阵(对称正定)
|Σ|: 协方差矩阵的行列式
μ: n 维均值向量
Σ: n×n 协方差矩阵(对称正定)
|Σ|: 协方差矩阵的行列式
二维高斯示例——身高与体重的联合分布:
μ = [170, 65](身高 170cm,体重 65kg)
Σ = [[36, 15],(身高方差=36, 协方差=15)
[15, 25]](体重方差=25)
相关系数 ρ = Cov/(σ₁σ₂) = 15/(6×5) = 0.5(中等正相关)
计算 x = [175, 70] 处的概率密度:
x - μ = [5, 5]
|Σ| = 36×25 - 15² = 900 - 225 = 675
Σ⁻¹ = (1/675)[[25, -15], [-15, 36]]
(x-μ)ᵀΣ⁻¹(x-μ) = [5,5] × (1/675)[[25,-15],[-15,36]] × [5,5]ᵀ
= (1/675) × [5×25+5×(-15), 5×(-15)+5×36] × [5,5]ᵀ
= (1/675) × [50, 105] × [5,5]ᵀ
= (1/675) × (250 + 525) = 775/675 = 1.148
p(175,70) = 1/(2π×√675) × exp(-0.574)
= 1/(2π×25.98) × 0.563 = 0.00613 × 0.563 = 0.00345
μ = [170, 65](身高 170cm,体重 65kg)
Σ = [[36, 15],(身高方差=36, 协方差=15)
[15, 25]](体重方差=25)
相关系数 ρ = Cov/(σ₁σ₂) = 15/(6×5) = 0.5(中等正相关)
计算 x = [175, 70] 处的概率密度:
x - μ = [5, 5]
|Σ| = 36×25 - 15² = 900 - 225 = 675
Σ⁻¹ = (1/675)[[25, -15], [-15, 36]]
(x-μ)ᵀΣ⁻¹(x-μ) = [5,5] × (1/675)[[25,-15],[-15,36]] × [5,5]ᵀ
= (1/675) × [5×25+5×(-15), 5×(-15)+5×36] × [5,5]ᵀ
= (1/675) × [50, 105] × [5,5]ᵀ
= (1/675) × (250 + 525) = 775/675 = 1.148
p(175,70) = 1/(2π×√675) × exp(-0.574)
= 1/(2π×25.98) × 0.563 = 0.00613 × 0.563 = 0.00345
3.4 指数分布 Exp(λ)
p(x) = λe^(-λx),x ≥ 0
E[X] = 1/λ,Var(X) = 1/λ²
描述事件发生的等待时间(无记忆性)
E[X] = 1/λ,Var(X) = 1/λ²
描述事件发生的等待时间(无记忆性)
AI 应用:用户请求到达间隔建模。若平均每秒 5 个请求(λ=5),两次请求间隔 ~ Exp(5),平均间隔 0.2 秒。用于 API 限流、负载均衡决策。
四、信息论中的分布度量
4.1 KL 散度
KL(P||Q) = Σᵢ P(i) × ln(P(i)/Q(i))
衡量分布 Q 与"真实"分布 P 的差异。
KL ≥ 0,当且仅当 P = Q 时 KL = 0。
注意:KL(P||Q) ≠ KL(Q||P)(不对称!)
衡量分布 Q 与"真实"分布 P 的差异。
KL ≥ 0,当且仅当 P = Q 时 KL = 0。
注意:KL(P||Q) ≠ KL(Q||P)(不对称!)
数值示例——模型输出与真实分布的偏差:
3 分类任务,真实标签是第 1 类。
P = [1.0, 0.0, 0.0](独热编码)
Q₁ = [0.8, 0.1, 0.1](较好的模型)
Q₂ = [0.4, 0.3, 0.3](较差的模型)
但 P 含 0,ln(0) 未定义。实际中 P 是独热时 KL 退化为交叉熵:
KL(P||Q₁) = 1.0 × ln(1.0/0.8) = ln(1.25) = 0.223
KL(P||Q₂) = 1.0 × ln(1.0/0.4) = ln(2.5) = 0.916
更一般地:P = [0.7, 0.2, 0.1], Q = [0.5, 0.3, 0.2]
KL(P||Q) = 0.7×ln(0.7/0.5) + 0.2×ln(0.2/0.3) + 0.1×ln(0.1/0.2)
= 0.7×0.336 + 0.2×(-0.405) + 0.1×(-0.693)
= 0.235 - 0.081 - 0.069 = 0.085
3 分类任务,真实标签是第 1 类。
P = [1.0, 0.0, 0.0](独热编码)
Q₁ = [0.8, 0.1, 0.1](较好的模型)
Q₂ = [0.4, 0.3, 0.3](较差的模型)
但 P 含 0,ln(0) 未定义。实际中 P 是独热时 KL 退化为交叉熵:
KL(P||Q₁) = 1.0 × ln(1.0/0.8) = ln(1.25) = 0.223
KL(P||Q₂) = 1.0 × ln(1.0/0.4) = ln(2.5) = 0.916
更一般地:P = [0.7, 0.2, 0.1], Q = [0.5, 0.3, 0.2]
KL(P||Q) = 0.7×ln(0.7/0.5) + 0.2×ln(0.2/0.3) + 0.1×ln(0.1/0.2)
= 0.7×0.336 + 0.2×(-0.405) + 0.1×(-0.693)
= 0.235 - 0.081 - 0.069 = 0.085
AI 应用——VAE 中的 KL 散度:
VAE 的损失 = 重建损失 + β × KL(q(z|x) || p(z))
q(z|x) = N(μ_enc, σ²_enc)(编码器输出)
p(z) = N(0, I)(先验)
KL(N(μ,σ²) || N(0,1)) = -½ Σⱼ (1 + ln(σⱼ²) - μⱼ² - σⱼ²)
若编码器对某个样本输出 μ=[0.5, -0.3], σ²=[0.8, 1.2]:
KL = -½[(1+ln0.8 - 0.25 - 0.8) + (1+ln1.2 - 0.09 - 1.2)]
= -½[(1-0.223-0.25-0.8) + (1+0.182-0.09-1.2)]
= -½[(-0.273) + (-0.108)]
= -½ × (-0.381) = 0.191
KL 越大,编码器的输出越偏离标准正态→惩罚越强。
VAE 的损失 = 重建损失 + β × KL(q(z|x) || p(z))
q(z|x) = N(μ_enc, σ²_enc)(编码器输出)
p(z) = N(0, I)(先验)
KL(N(μ,σ²) || N(0,1)) = -½ Σⱼ (1 + ln(σⱼ²) - μⱼ² - σⱼ²)
若编码器对某个样本输出 μ=[0.5, -0.3], σ²=[0.8, 1.2]:
KL = -½[(1+ln0.8 - 0.25 - 0.8) + (1+ln1.2 - 0.09 - 1.2)]
= -½[(1-0.223-0.25-0.8) + (1+0.182-0.09-1.2)]
= -½[(-0.273) + (-0.108)]
= -½ × (-0.381) = 0.191
KL 越大,编码器的输出越偏离标准正态→惩罚越强。
五、代码验证(C# / Rust)
C#(.NET 10)
// dotnet run 即可执行
// 工具函数
double Erf(double x)
{
double sign = x < 0 ? -1 : 1; x = Math.Abs(x);
double t = 1.0 / (1.0 + 0.3275911 * x);
return sign * (1.0 - (((((1.061405429*t - 1.453152027)*t)
+ 1.421413741)*t - 0.284496736)*t + 0.254829592)*t * Math.Exp(-x*x));
}
double NormPdf(double x, double mu, double s)
=> Math.Exp(-0.5 * Math.Pow((x-mu)/s, 2)) / (s * Math.Sqrt(2*Math.PI));
double NormCdf(double x, double mu, double s)
=> 0.5 * (1 + Erf((x - mu) / (s * Math.Sqrt(2))));
long Comb(int n, int k) {
if (k > n-k) k = n-k; long r = 1;
for (int i = 0; i < k; i++) r = r*(n-i)/(i+1); return r; }
double BinPmf(int k, int n, double p) => Comb(n,k)*Math.Pow(p,k)*Math.Pow(1-p,n-k);
// ===== 贝叶斯公式 =====
double pD = 0.001, pPosD = 0.99, pPosH = 0.05;
double pPos = pPosD*pD + pPosH*(1-pD);
double pDPos = pPosD*pD / pPos;
Console.WriteLine($"P(病|阳性) = {pDPos:F4} = {pDPos*100:F2}%");
// ===== 高斯分布 =====
double mu = 170, sigma = 6;
Console.WriteLine($"\nN({mu},{sigma}²) 在 x=180 的密度: {NormPdf(180,mu,sigma):F4}");
Console.WriteLine($"P(X > 182) = {1-NormCdf(182,mu,sigma):F4}");
Console.WriteLine($"P(164 < X < 176) = {NormCdf(176,mu,sigma)-NormCdf(164,mu,sigma):F4}");
// ===== 二项分布 =====
Console.WriteLine($"\nBinomial(n=20, p=0.92):");
Console.WriteLine($"P(X=18) = {BinPmf(18,20,0.92):F4}");
double pGe = BinPmf(18,20,0.92)+BinPmf(19,20,0.92)+BinPmf(20,20,0.92);
Console.WriteLine($"P(X>=18) = {pGe:F4}");
// ===== 多维高斯 =====
double[] mu2={170,65}; double[,] cov={{36,15},{15,25}}; double[] x2={175,70};
double det = cov[0,0]*cov[1,1]-cov[0,1]*cov[1,0];
double[] d = {x2[0]-mu2[0], x2[1]-mu2[1]};
double mah = (cov[1,1]*d[0]*d[0]-2*cov[0,1]*d[0]*d[1]+cov[0,0]*d[1]*d[1])/det;
Console.WriteLine($"\n二维高斯在 [{x2[0]},{x2[1]}] 的密度: {Math.Exp(-0.5*mah)/(2*Math.PI*Math.Sqrt(det)):F5}");
// ===== KL 散度 =====
double[] P={0.7,0.2,0.1}, Q={0.5,0.3,0.2};
double kl=0; for(int i=0;i<3;i++) kl+=P[i]*Math.Log(P[i]/Q[i]);
Console.WriteLine($"\nKL(P||Q) = {kl:F4}");
// ===== VAE KL 散度 =====
double[] muE={0.5,-0.3}, s2={0.8,1.2};
double klV=0; for(int i=0;i<2;i++){ double lv=Math.Log(s2[i]); klV+=1+lv-muE[i]*muE[i]-s2[i]; }
Console.WriteLine($"VAE KL = {klV*-0.5:F4}");
Rust
use std::f64::consts::PI;
fn erf(x: f64) -> f64 {
let sign = if x < 0.0 { -1.0 } else { 1.0 };
let x = x.abs();
let t = 1.0 / (1.0 + 0.3275911 * x);
sign * (1.0 - 1.061405429_f64.mul_add(t, -1.453152027)
.mul_add(t, 1.421413741).mul_add(t, -0.284496736)
.mul_add(t, 0.254829592) * t * (-x*x).exp())
}
fn norm_pdf(x: f64, mu: f64, s: f64) -> f64 {
(-0.5 * ((x-mu)/s).powi(2)).exp() / (s * (2.0*PI).sqrt())
}
fn norm_cdf(x: f64, mu: f64, s: f64) -> f64 {
0.5 * (1.0 + erf((x - mu) / (s * 2.0_f64.sqrt())))
}
fn comb(n: u64, k: u64) -> u64 {
let k = k.min(n - k);
(0..k).fold(1_u64, |r, i| r * (n - i) / (i + 1))
}
fn binom_pmf(k: u64, n: u64, p: f64) -> f64 {
comb(n, k) as f64 * p.powi(k as i32) * (1.0-p).powi((n-k) as i32)
}
fn main() {
// ===== 贝叶斯公式 =====
let (p_d, p_pos_d, p_pos_h) = (0.001_f64, 0.99, 0.05);
let p_pos = p_pos_d.mul_add(p_d, p_pos_h*(1.0-p_d));
let p_d_pos = p_pos_d*p_d / p_pos;
println!("P(病|阳性) = {p_d_pos:.4} = {:.2}%", p_d_pos*100.0);
// ===== 高斯分布 =====
let (mu, sig) = (170.0_f64, 6.0);
println!("\nN({mu},{sig}²) 在 x=180 的密度: {:.4}", norm_pdf(180.0, mu, sig));
println!("P(X > 182) = {:.4}", 1.0 - norm_cdf(182.0, mu, sig));
println!("P(164 < X < 176) = {:.4}",
norm_cdf(176.0, mu, sig) - norm_cdf(164.0, mu, sig));
// ===== 二项分布 =====
println!("\nBinomial(n=20, p=0.92):");
println!("P(X=18) = {:.4}", binom_pmf(18, 20, 0.92));
let p_ge = binom_pmf(18,20,0.92)+binom_pmf(19,20,0.92)+binom_pmf(20,20,0.92);
println!("P(X>=18) = {p_ge:.4}");
// ===== 多维高斯 =====
let (mu2, cov, x2) = ([170.0,65.0_f64],[[36.0,15.0],[15.0,25.0_f64]],[175.0,70.0_f64]);
let det = cov[0][0]*cov[1][1] - cov[0][1]*cov[1][0];
let d = [x2[0]-mu2[0], x2[1]-mu2[1]];
let mah = (cov[1][1]*d[0]*d[0]-2.0*cov[0][1]*d[0]*d[1]+cov[0][0]*d[1]*d[1])/det;
let p_x2 = (-0.5*mah).exp() / (2.0*PI*det.sqrt());
println!("\n二维高斯在 [{},{}] 的密度: {p_x2:.5}", x2[0], x2[1]);
// ===== KL 散度 =====
let p_arr = [0.7, 0.2, 0.1_f64];
let q_arr = [0.5, 0.3, 0.2_f64];
let kl: f64 = (0..3).map(|i| p_arr[i]*(p_arr[i]/q_arr[i]).ln()).sum();
println!("\nKL(P||Q) = {kl:.4}");
// ===== VAE KL 散度 =====
let mu_e = [0.5, -0.3_f64];
let s2 = [0.8, 1.2_f64];
let kl_v: f64 = (0..2).map(|i| 1.0+s2[i].ln()-mu_e[i]*mu_e[i]-s2[i]).sum::<f64>() * -0.5;
println!("VAE KL = {kl_v:.4}");
}