【AI】通俗详解狄利克雷分布(Python 应用示例)
之前看文章也有看到过狄利克雷分布,当时学习了一下似乎理解了,最近又看到了,有点忘了,鉴于老是遇见这特别的缘分,还是记录下来,便于后续回顾。
狄利克雷分布可以通俗地理解为:它是用来描述“把一个整体分成多个部分,每个部分占多少比例”这种分配情况的分布。你可以把它看作是“分布的概率分布”。
1、定义:从“切饼”说起
想象一下,你需要把一块 1 公斤重的蛋糕分给 KKK 个人。分蛋糕的方式有无数种,而 狄利克雷分布就是用来描述这些“分法”本身的概率规律。
要精确描述它,我们引入一个 KKK 维的向量 p=(p1,p2,…,pK)\boldsymbol{p}=(p_1,p_2,\dots,p_K)p=(p1,p2,…,pK),其中 pip_ipi 代表分配给第 iii 个人的比例,它们必须满足和为 111,即 ∑i=1Kpi=1\sum_{i=1}^{K} p_i = 1∑i=1Kpi=1。
狄利克雷分布就是这个向量 p\boldsymbol{p}p 的概率密度函数,由浓度参数 α=(α1,α2,…,αK)\boldsymbol{\alpha}=(\alpha_1,\alpha_2,\dots,\alpha_K)α=(α1,α2,…,αK) 控制,其概率密度函数为:
Dir(p∣α)=Γ(∑i=1Kαi)∏i=1KΓ(αi)∏i=1Kpiαi−1\text{Dir}(\boldsymbol{p}\mid\boldsymbol{\alpha}) = \frac{\Gamma\left(\sum_{i=1}^{K}\alpha_i\right)}{\prod_{i=1}^{K}\Gamma(\alpha_i)}\prod_{i=1}^{K} p_i^{\alpha_i-1}Dir(p∣α)=∏i=1KΓ(αi)Γ(∑i=1Kαi)i=1∏Kpiαi−1
这个公式看起来很复杂,但可以分步来理解:
(1)p\boldsymbol{p}p:就是我们关心的那个“分饼方案”,即一组比例 (p1,…,pK)(p_1,\dots,p_K)(p1,…,pK);
(2)α\boldsymbol{\alpha}α:这是决定“分饼”偏好的超参数。如果 αi\alpha_iαi 很大,就意味着第 iii 块更容易分到大份;
(3)Γ(⋅)\Gamma(\cdot)Γ(⋅):这是伽马函数,可以看作阶乘在实数上的推广,它的作用主要是为了确保整个概率的积分为 111,是一个“归一化”的常数;
2、伽马函数
伽马函数通常记作 Γ(z)\Gamma(z)Γ(z),其数学定义是一个反常积分:
Γ(z)=∫0∞tz−1e−tdt,z>0\Gamma(z) = \int_{0}^{\infty} t^{z-1} e^{-t} dt,\quad z>0Γ(z)=∫0∞tz−1e−tdt,z>0 这个积分看起来可能有些抽象,但它定义了一个平滑的曲线,将离散的阶乘概念连续化了。
伽马函数最重要的一个性质就是它对阶乘的完美兼容:
Γ(n)=(n−1)!\Gamma(n) = (n-1)!Γ(n)=(n−1)! 也就是说,当 nnn 是正整数时,Γ(n)\Gamma(n)Γ(n) 等于 n−1n-1n−1 的阶乘。例如:
Γ(1)=1\Gamma(1) = 1Γ(1)=1
Γ(2)=1\Gamma(2) = 1Γ(2)=1
Γ(3)=1×2=2\Gamma(3) = 1×2=2Γ(3)=1×2=2
Γ(4)=1×2×3=6\Gamma(4) = 1×2×3=6Γ(4)=1×2×3=6
关键性质: 它满足递推关系 Γ(z+1)=zΓ(z)\Gamma(z+1) = z\Gamma(z)Γ(z+1)=zΓ(z)
3、与 Beta 分布的关系
当我们只把饼分两块时,令 K=2K=2K=2,此时狄利克雷分布退化为 Beta 分布:
类别 1 的比例:p1=pp_1 = pp1=p;
类别 2 的比例:p2=1−pp_2 = 1-pp2=1−p;
对应的浓度参数:α1=α, α2=β\alpha_1 = \alpha,\ \alpha_2 = \betaα1=α, α2=β
将 K=2K=2K=2 代入狄利克雷分布的公式:
Dir(p1,p2∣α1,α2)=Γ(α1+α2)Γ(α1)Γ(α2)p1α1−1p2α2−1\operatorname{Dir}(p_1,p_2|\alpha_1,\alpha_2) = \frac{\Gamma(\alpha_1+\alpha_2)}{\Gamma(\alpha_1)\Gamma(\alpha_2)} p_1^{\alpha_1-1} p_2^{\alpha_2-1}Dir(p1,p2∣α1,α2)=Γ(α1)Γ(α2)Γ(α1+α2)p1α1−1p2α2−1 将 p1=pp_1 = pp1=p、p2=1−pp_2 = 1-pp2=1−p、α1=α, α2=β\alpha_1 = \alpha,\ \alpha_2 = \betaα1=α, α2=β 带入上式,得到:
Dir(p1,p2∣α1,α2)=Γ(α+β)Γ(α)Γ(β)pα−1(1−p)β−1=Beta(p∣α,β)\operatorname{Dir}(p_1,p_2|\alpha_1,\alpha_2) =\frac{\Gamma(\alpha+\beta)}{\Gamma(\alpha)\Gamma(\beta)} p^{\alpha-1} (1-p)^{\beta-1}=\operatorname{Beta}(p|\alpha,\beta)Dir(p1,p2∣α1,α2)=Γ(α)Γ(β)Γ(α+β)pα−1(1−p)β−1=Beta(p∣α,β)
4、应用实例
假设一个水果摊老板想预测未来一周顾客购买苹果、香蕉、樱桃三种水果的比例。他把这个比例记为向量 p=(p1,p2,p3)\boldsymbol{p}=(p_1,p_2,p_3)p=(p1,p2,p3),三者加和为1。
老板根据以往经验,认为苹果不太热门,香蕉最畅销,樱桃居中。他用一个狄利克雷分布来刻画自己的先验信念,令浓度参数 α=(2,5,3)\boldsymbol{\alpha}=(2,5,3)α=(2,5,3),这里 α0=∑αi=10\alpha_0 = \sum \alpha_i = 10α0=∑αi=10。
4.1、概率密度函数:具体的形状是怎样的?
代入公式,K=3K=3K=3:
f(p1,p2,p3)=Γ(10)Γ(2)Γ(5)Γ(3)⋅p12−1p25−1p33−1f(p_1,p_2,p_3) = \frac{\Gamma(10)}{\Gamma(2)\Gamma(5)\Gamma(3)} \cdot p_1^{2-1} p_2^{5-1} p_3^{3-1}f(p1,p2,p3)=Γ(2)Γ(5)Γ(3)Γ(10)⋅p12−1p25−1p33−1 计算伽马函数(整数时等于阶乘):Γ(10)=9!=362880\Gamma(10) = 9! = 362880Γ(10)=9!=362880,Γ(2)=1!=1\Gamma(2) = 1! = 1Γ(2)=1!=1,Γ(5)=4!=24\Gamma(5) = 4! = 24Γ(5)=4!=24,Γ(3)=2!=2\Gamma(3) = 2! = 2Γ(3)=2!=2。归一化常数为 362880/(1×24×2)=7560362880/(1 \times 24 \times 2) = 7560362880/(1×24×2)=7560。
所以该老板的先验分布密度为:
f(p1,p2,p3)=7560⋅p11⋅p24⋅p32f(p_1,p_2,p_3) = 7560 \cdot p_1^{1} \cdot p_2^{4} \cdot p_3^{2}f(p1,p2,p3)=7560⋅p11⋅p24⋅p32 这个式子告诉我们,香蕉( p2p_2p2 )的指数最高(4次方),密度在香蕉占比较大时会明显更高,这完全对应了老板“香蕉最好卖”的主观判断。
4.2、期望:平均占比是多少?
狄利克雷分布的期望公式非常简洁,就是“自己的参数占总参数的比值”:
E[pi]=αiα0E[p_i] = \frac{\alpha_i}{\alpha_0}E[pi]=α0αi 代入数值:
苹果:E[p1]=2/10=0.2E[p_1] = 2/10 = 0.2E[p1]=2/10=0.2
香蕉:E[p2]=5/10=0.5E[p_2] = 5/10 = 0.5E[p2]=5/10=0.5
樱桃:E[p3]=3/10=0.3E[p_3] = 3/10 = 0.3E[p3]=3/10=0.3
这组期望就是老板“最有可能”的进货比例参考。
4.3、方差:这个估计有多不确定?
方差衡量老板对自己判断的信心。方差越大,表示越没把握。公式为:
Var[pi]=αi(α0−αi)α02(α0+1)\operatorname{Var}[p_i] = \frac{\alpha_i(\alpha_0 - \alpha_i)}{\alpha_0^2(\alpha_0 + 1)}Var[pi]=α02(α0+1)αi(α0−αi) 代入计算香蕉(i=2i=2i=2)的方差:
Var[p2]=5×(10−5)102×(10+1)=25100×11=251100≈0.0227\operatorname{Var}[p_2] = \frac{5 \times (10-5)}{10^2 \times (10+1)}= \frac{25}{100 \times 11}= \frac{25}{1100} \approx 0.0227Var[p2]=102×(10+1)5×(10−5)=100×1125=110025≈0.0227 标准差约为 0.0227≈0.15\sqrt{0.0227} \approx 0.150.0227≈0.15。
这意味着,虽然老板预测香蕉占 50%,但真实比例有较大可能在 35%~65% 之间波动。如果老板想更有底气,可以把所有 α\alphaα 整体放大(比如乘以10),此时 α0\alpha_0α0 变大,方差会急剧缩小(因为分母有 α02\alpha_0^2α02),代表信念更坚定。
4.4、边缘分布:只看苹果,不看香蕉樱桃怎么算?
很多时候老板只关心“苹果 vs 非苹果”。这时需要把香蕉和樱桃的比例合并。
狄利克雷分布有一个极好的性质:边缘分布仍然是狄利克雷(或贝塔)分布。 把第 2 和第 3 类合并,新的浓度参数就是两者相加。
苹果的边际分布为:
p1∼Beta(α1,α2+α3)=Beta(2,5+3)=Beta(2,8)p_1 \sim \operatorname{Beta}(\alpha_1,\alpha_2+\alpha_3) = \operatorname{Beta}(2,5+3) = \operatorname{Beta}(2,8)p1∼Beta(α1,α2+α3)=Beta(2,5+3)=Beta(2,8) 其密度函数为:
f(p1)=Γ(10)Γ(2)Γ(8)p11(1−p1)7f(p_1) = \frac{\Gamma(10)}{\Gamma(2)\Gamma(8)} p_1^1 (1-p_1)^7f(p1)=Γ(2)Γ(8)Γ(10)p11(1−p1)7 这完全退化为一个关于单变量 p1p_1p1 的分布。这也再次印证了之前说的:Beta 分布就是 K=2K=2K=2 时的狄利克雷分布。
4.5、共轭性质:来了新数据怎么更新?
这是狄利克雷分布最迷人的数学特性。假设老板营业一周后,真实统计到顾客购买三种水果的次数为:苹果 3 次,香蕉 2 次,樱桃 5 次,记为数据 x=(3,2,5)\mathbf{x} = (3,2,5)x=(3,2,5)。
在贝叶斯框架下,后验分布 = 先验分布 + 观测数据。 由于共轭性,后验依然是一个狄利克雷分布,只需把参数相加:
α后验=α先验+x=(2+3, 5+2, 3+5)=(5,7,8)\boldsymbol{\alpha}_{\text{后验}} = \boldsymbol{\alpha}_{\text{先验}} + \mathbf{x} = (2+3,\,5+2,\,3+5) = (5,7,8)α后验=α先验+x=(2+3,5+2,3+5)=(5,7,8) 此时新的总参数 α0′=20\alpha_0' = 20α0′=20。
更新后的期望变为:
苹果:5/20=0.255/20 = 0.255/20=0.25(从0.2上升)
香蕉:7/20=0.357/20 = 0.357/20=0.35(从0.5大幅下降)
樱桃:8/20=0.48/20 = 0.48/20=0.4(从0.3上升)
由此可见,虽然老板先验觉得香蕉最好卖(给了 5 的权重),但实际一周数据中樱桃卖了 5 次,香蕉只卖了 2 次。数据的力量“拉回”了先验的偏见,后验分布显示樱桃变成了最畅销的水果。这种“先验知识 + 数据证据 = 更新后的知识”的闭环,正是狄利克雷分布作为多项式分布共轭先验的实战价值所在。更新过程无需复杂的数值积分,直接做一次加法就完成了机器学习中的“参数更新”,极其高效。
5、Python 实现
代码实现:
#%% 基础实例化与统计量计算=============================================================
import numpy as np
from scipy.stats import dirichlet
# 定义浓度参数(对应苹果、香蕉、樱桃的先验信念)
alpha = np.array([2, 5, 3])
# 实例化狄利克雷分布(返回一个“冻结”的分布对象)
dist = dirichlet(alpha)
# 查看分布的基本属性
print("浓度参数:", alpha)
print("期望(平均占比):", dist.mean()) # [0.2, 0.5, 0.3]
print("方差:", dist.var()) # [0.016, 0.0227, 0.018]
# 计算某个特定比例向量的概率密度(需确保向量和为1)
p_point = np.array([0.2, 0.5, 0.3])
print(f"\n在 p={p_point} 处的概率密度值: {dist.pdf(p_point):.4f}")
#%% 随机采样(仿真生成“可能的销售比例”)====================================================
# 方法一:使用 dist.rvs() 生成样本
samples = dist.rvs(size=10) # 生成 10 组比例
print("\n随机生成的 10 组销售比例:\n", np.round(samples, 3))
# 方法二:直接使用 NumPy(效果等价)
samples_np = np.random.dirichlet(alpha, size=10)
print("\nNumPy 生成的样本(验证一致性):\n", np.round(samples_np, 3))
#%% 可视化边际分布(验证退化为 Beta 分布)=================================================
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import dirichlet, beta
# ---------- 设置中文字体(Windows 下可用 SimHei 或 Microsoft YaHei) ----------
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定默认字体为黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
# ---------- 实例化狄利克雷分布 ----------
alpha = np.array([2, 5, 3])
dist = dirichlet(alpha)
# ---------- 采样与绘图 ----------
samples_large = dist.rvs(size=5000)
plt.figure(figsize=(8, 4), dpi=300)
plt.hist(samples_large[:, 0], bins=40, density=True, alpha=0.7, label='采样直方图')
p1_vals = np.linspace(0, 1, 100)
plt.plot(p1_vals, beta.pdf(p1_vals, 2, 8), 'r-', linewidth=2, label='Beta(2,8) 理论密度')
plt.xlabel('苹果占比 (p1)')
plt.ylabel('概率密度')
plt.title('狄利克雷分布第1分量的边际分布')
plt.legend()
plt.show()
#%% 共轭更新(后验实例化)==============================================================
# 观测计数
data = np.array([3, 2, 5])
# 后验参数 = 先验参数 + 观测计数
alpha_posterior = alpha + data
# 实例化后验分布
post_dist = dirichlet(alpha_posterior)
print("\n后验浓度参数:", alpha_posterior) # [5, 7, 8]
print("后验期望(更新后的预测):", post_dist.mean()) # [0.25, 0.35, 0.4]
输出显示:
浓度参数: [2 5 3]
期望(平均占比): [0.2 0.5 0.3]
方差: [0.01454545 0.02272727 0.01909091]
在 p=[0.2 0.5 0.3] 处的概率密度值: 8.5050
随机生成的 10 组销售比例:
[[0.203 0.482 0.315]
[0.017 0.647 0.336]
[0.042 0.592 0.366]
[0.258 0.63 0.111]
[0.06 0.561 0.379]
[0.188 0.508 0.304]
[0.189 0.628 0.183]
[0.178 0.494 0.328]
[0.073 0.878 0.049]
[0.151 0.454 0.395]]
NumPy 生成的样本(验证一致性):
[[0.095 0.441 0.464]
[0.037 0.609 0.353]
[0.141 0.663 0.196]
[0.136 0.604 0.26 ]
[0.096 0.441 0.463]
[0.087 0.726 0.187]
[0.245 0.643 0.112]
[0.125 0.733 0.142]
[0.111 0.511 0.378]
[0.248 0.243 0.509]]
后验浓度参数: [5 7 8]
后验期望(更新后的预测): [0.25 0.35 0.4 ]
图像显示:

生活不易,老板叹气 〒▽〒
更多推荐


所有评论(0)