概率论深度指南

文档概述

本文档系统梳理概率论的核心知识体系,涵盖从公理化基础到高级概率分布族的完整理论框架,为机器学习与人工智能研究提供坚实的数学基础。本指南特别强调直观理解、代码实现和ML应用场景,让读者不仅”知道”,更能”动手”。

关键词速查表

序号关键词英文核心概念
1概率空间Probability Space
2随机变量Random Variable
3条件概率Conditional Probability
4贝叶斯定理Bayes’ Theorem
5期望值Expectation
6方差Variance
7协方差Covariance
8大数定律Law of Large Numbers
9中心极限定理Central Limit Theorem
10指数族Exponential Family
11共轭先验Conjugate PriorBeta-Binomial, Dirichlet-Multinomial
12测度论Measure TheoryLebesgue积分基础

零、概率论入门:用生活案例讲清楚

0.1 为什么你需要懂概率论?

很多同学学概率论的时候会有个疑问:这玩意儿买菜用得上吗?说实话,买菜确实用不上。但如果你想做机器学习、做数据分析、训练神经网络,概率论就是你的”内力”——不是招式,但没它你使不出任何厉害的武功。

举个实际例子。你训练一个垃圾邮件分类器,输入是邮件内容,输出是”是垃圾邮件”或”不是垃圾邮件”。但模型不可能100%准确,它会给你一个概率:P(垃圾邮件|邮件内容)。这个概率怎么来的?怎么训练这个模型让它的判断更准?这些问题,都需要概率论来回答。

再比如,你想预测明天的股价,或者估计某个用户会不会点击广告——本质上都是概率问题。机器学习的核心,就是用概率论的语言来描述不确定性,然后用数据来学习这个概率分布。

0.2 掷骰子:最直观的概率入门

先从最简单的东西开始:一颗公平的六面骰子。

什么是概率?

掷一次骰子,出现”3”这个事件记作 。在公平骰子下,每个面出现的可能性一样,所以:

这就是古典概型——所有基本事件等可能发生。

用Python验证:

import numpy as np
 
# 模拟掷骰子10000次
np.random.seed(42)
rolls = np.random.randint(1, 7, size=10000)
 
# 统计每个数字出现的频率
unique, counts = np.unique(rolls, return_counts=True)
for num, count in zip(unique, counts):
    print(f"数字{num}: 出现{count}次, 频率={count/10000:.4f}")
 
# 输出会接近 1/6 ≈ 0.1667

什么是随机变量?

“骰子的点数”就是一个随机变量。它不是随机的,而是用一个数值来表示随机实验的结果。我们用大写字母 来表示随机变量:

离散 vs 连续的区别:

骰子的点数只能取1-6这6个整数,这就是离散随机变量。如果问”某个人身高是多少”,答案可以是1.73米、1.731米、1.7312米……有无穷多种可能,这就是连续随机变量

关键区别:离散变量可以一个一个数出来,连续变量只能取区间里的任何值。

0.3 抛硬币:理解概率分布

抛一次硬币,正面朝上的概率记作 (公平硬币的话 )。

# 用NumPy模拟抛硬币
np.random.seed(123)
flips = np.random.rand(1000)  # 生成[0,1)之间的随机数
heads = (flips < 0.5).astype(int)  # 小于0.5算正面
 
print(f"正面出现次数: {heads.sum()}")
print(f"正面频率: {heads.mean():.4f}")  # 应该接近0.5

伯努利分布(Bernoulli Distribution):

抛一次硬币就是最简单的伯努利实验:

二项分布(Binomial Distribution):

次硬币,正面出现 次的概率:

这个公式什么意思? 是”从 次中选 次是正面”的选法数量, 是这 次正面的概率, 是剩下 次反面的概率。

from scipy import stats
 
# 抛10次硬币,恰好5次正面的概率
n, p = 10, 0.5
k = 5
prob = stats.binom.pmf(k, n, p)
print(f"P(X=5) = {prob:.4f}")  # ≈ 0.2461
 
# 绘制二项分布的概率质量函数
import matplotlib.pyplot as plt
 
k_values = np.arange(0, 11)
probs = stats.binom.pmf(k_values, n, p)
plt.bar(k_values, probs)
plt.xlabel('正面次数 k')
plt.ylabel('概率 P(X=k)')
plt.title('二项分布 B(10, 0.5)')
plt.show()

0.4 条件概率:已知信息改变概率

什么是条件概率?

假设你知道今天早上堵车了(事件B),在这个信息下,你迟到的概率(事件A)是多少?这就是条件概率 ——在B发生的条件下A发生的概率。

用文氏图理解:就是在B这个圆里,A和B重叠部分占B的比例。

经典例子:体检结果

假设有一种疾病:

  • 患病率(先验概率):(1%的人患病)
  • 检测准确率:(患病者99%会检测阳性)
  • 误报率:(健康者5%会误报阳性)

如果你检测结果阳性,你真正患病的概率是多少?

# 使用贝叶斯公式计算
P_disease = 0.01
P_positive_given_disease = 0.99
P_positive_given_healthy = 0.05
 
# 全概率公式
P_positive = (P_positive_given_disease * P_disease + 
              P_positive_given_healthy * (1 - P_disease))
 
# 贝叶斯公式
P_disease_given_positive = (P_positive_given_disease * P_disease) / P_positive
 
print(f"检测阳性时真正患病的概率: {P_disease_given_positive:.4f}")
# 输出约 0.1664 —— 只有16.6%!

这个结果很反直觉对吧?检测阳性后,你可能觉得自己多半中标了,但实际上因为患病率很低(1%),假阳性(健康人误报)的影响很大。

直觉陷阱:我们总是高估小概率事件在已知信息下的影响力。条件概率告诉我们,已知部分信息后要重新”校准”你的信念。


一、概率空间与公理化体系

1.1 概率论的三元组结构

现代概率论建立在测度论的基础之上,采用公理化方法构建完整的理论体系。概率空间由三元组 定义。

样本空间 表示所有可能基本结果的集合。

实验样本空间
抛硬币
掷骰子
测量身高(米)
掷两枚骰子

σ-代数 是样本空间上可测的子集族,必须满足:

  1. (包含空集)
  2. ,则 (对补运算封闭)
  3. ,则 (对可数并封闭)

σ-代数定义了哪些事件可以被赋予概率。在连续情形(如身高),不是所有子集都有概率——我们只关心”Borel可测”的集合。

概率测度 满足Kolmogorov公理:

公理含义
非负性
归一性
可数可加性 两两不相交)

1.2 条件概率与乘法公式

条件概率定义:

乘法公式(Chain Rule):

对于多个事件:

独立性

事件 独立,当且仅当:

这也等价于(当 时):

独立性意味着知道B发生,不会改变A的概率。

# 验证独立性
# 抛两枚硬币:A = "第一枚正面",B = "第二枚正面"
# 这两个事件独立吗?
 
p_A = 0.5
p_B = 0.5
p_A_and_B = 0.25  # 两枚都正面的概率
 
is_independent = np.isclose(p_A_and_B, p_A * p_B)
print(f"独立吗?{is_independent}")  # True

1.3 全概率公式

全概率公式是贝叶斯定理的”地基”:

其中 是样本空间的一个划分(互不相交、合并为整个空间)。

直观理解:要计算事件B发生的总概率,就考虑B在各种”场景”下发生的概率,然后按场景的可能性加权求和。

# 全概率公式的例子:混合盒子问题
# 盒子A有80%红球、20%蓝球;盒子B有40%红球、60%蓝球
# 随机选一个盒子(各50%概率),从中摸一个球
 
P_box_A = 0.5
P_box_B = 0.5
P_red_given_A = 0.8
P_red_given_B = 0.4
 
# 摸到红球的概率
P_red = P_red_given_A * P_box_A + P_red_given_B * P_box_B
print(f"摸到红球的概率: {P_red:.2f}")  # 0.6

二、贝叶斯定理与统计推断基础

2.1 贝叶斯定理——从怀疑到确信

贝叶斯定理是概率论中最重要的公式之一。用一句话概括:当新的证据出现时,如何更新我们对世界的看法?

定理导出

从条件概率出发:

用全概率公式展开,得到贝叶斯定理

在统计推断中的形式

术语含义通俗理解
先验概率(Prior)在看到数据之前,我们的信念是什么?
似然函数(Likelihood)如果参数真的是 ,这个数据出现的概率有多大?
后验概率(Posterior)看到数据后,我们应该相信什么?
边际似然(Evidence)这个数据出现的总概率(归一化常数)

生活类比:看病的过程就是贝叶斯推断。

  • 先验:你平时生病的概率(大多数人不太容易生病)
  • 似然:如果你真的病了,某种症状出现的概率
  • 后验:有了这个症状后,你真正生病的概率

医生看病,本质上就是在做贝叶斯推断!

2.2 为什么贝叶斯思维改变了我们思考问题的方式?

频率派 vs 贝叶斯派

  • 频率派( Frequentist):概率是长期重复实验的频率。参数是固定但未知的,我们需要用数据去”点估计”它。
  • 贝叶斯派(Bayesian):概率是信念的程度。参数本身是随机的,我们用概率分布来描述它。

贝叶斯思维的核心

  1. 一切皆是概率:不仅数据有随机性,未知的参数也可以用概率分布来描述。
  2. 先验的重要性:我们可以把领域知识或历史经验编码成先验分布。
  3. 更新信念:看到新数据后,用贝叶斯公式更新我们对参数的认知。

实际应用场景

场景贝叶斯思维的应用
垃圾邮件过滤先验:大多数邮件不是垃圾;似然:邮件中出现某些词的频率;后验:给定邮件内容,判断是垃圾邮件的概率
A/B测试先验:对新版本效果的信念;似然:实验数据;后验:新版本真的更好的概率
医学诊断先验:疾病患病率;似然:症状在有病/无病时的表现;后验:给定症状,患者患病的概率

2.3 共轭先验实战:Beta-Binomial共轭

在贝叶斯推断中,后验分布通常没有解析形式。但有一种特殊情况——共轭先验——可以让后验分布保持和先验相同的形式。

Beta-Binomial共轭是最经典的例子:

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
 
# 场景:估计一枚硬币正面朝上的概率 p
# 我们观测到 n 次抛掷,其中 k 次正面
 
# 先验:Beta(α, β) 分布
# Beta分布的概率密度函数
def beta_pdf(x, alpha, beta):
    return stats.beta.pdf(x, alpha, beta)
 
# 可视化不同先验
x = np.linspace(0, 1, 100)
priors = [(1, 1), (2, 2), (10, 10), (1, 5), (5, 1)]
labels = ['Beta(1,1) 无信息', 'Beta(2,2) 轻度不确定', 
          'Beta(10,10) 强烈相信接近0.5', 'Beta(1,5) 偏向反面', 'Beta(5,1) 偏向正面']
 
plt.figure(figsize=(10, 6))
for (a, b), label in zip(priors, labels):
    plt.plot(x, beta_pdf(x, a, b), label=label, linewidth=2)
plt.xlabel('p (正面概率)')
plt.ylabel('概率密度')
plt.title('Beta分布作为硬币概率的先验')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
 
print("""
# 共轭先验的更新公式
# 先验: p ~ Beta(α, β)
# 数据: k 次正面, n-k 次反面
# 后验: p | data ~ Beta(α + k, β + n - k)
""")

实际计算示例

def bayesian_coin_flip_update(alpha_prior, beta_prior, n_flips, k_heads):
    """
    贝叶斯更新:给定抛掷数据,更新硬币正面概率的分布
    
    参数:
        alpha_prior, beta_prior: 先验Beta分布参数
        n_flips: 抛掷总次数
        k_heads: 正面次数
    返回:
        后验Beta分布参数
    """
    alpha_post = alpha_prior + k_heads
    beta_post = beta_prior + (n_flips - k_heads)
    return alpha_post, beta_post
 
# 例子:抛10次硬币,7次正面
n_flips = 10
k_heads = 7
 
# 使用无信息先验 Beta(1, 1)
alpha_post, beta_post = bayesian_coin_flip_update(1, 1, n_flips, k_heads)
print(f"后验分布: Beta({alpha_post}, {beta_post})")
 
# 计算后验均值和95%可信区间
posterior_mean = alpha_post / (alpha_post + beta_post)
ci_low, ci_high = stats.beta.ppf([0.025, 0.975], alpha_post, beta_post)
print(f"后验均值: {posterior_mean:.4f}")
print(f"95%可信区间: [{ci_low:.4f}, {ci_high:.4f}]")
 
# 对比:频率派估计(最大似然估计)
mle_estimate = k_heads / n_flips
print(f"最大似然估计: {mle_estimate:.4f}")

为什么共轭先验有用?

  1. 计算简便:后验分布有解析形式,不需要数值近似
  2. 可解释性强:参数更新的意义很清晰(加数据)
  3. 递推更新:新来一批数据,直接在当前后验上加就行

2.4 从先验/后验/似然理解ML模型

在机器学习中,先验-似然-后验的框架无处不在:

线性回归的贝叶斯视角

  • 先验 :我们对系数 的先验信念(通常假设
  • 似然 :给定系数后,数据出现的概率
  • 后验 :看到数据后,系数应该是什么分布?

正则化的本质

L2正则化(岭回归)对应的是系数的高斯先验:

L1正则化(Lasso)对应的是系数的拉普拉斯先验:

所以,正则化项在贝叶斯框架下就是先验对参数空间的惩罚


三、大数定律与中心极限定理——为什么正态分布无处不在?

3.1 大数定律——重复出真知

弱大数定律(辛钦大数定律):

是独立同分布的随机变量,,则:

翻译成人话:样本均值会越来越接近真实的期望值

蒙特卡洛方法就是建立在这个定律上的

# 用蒙特卡洛方法估算圆周率 π
np.random.seed(42)
n_samples = 1000000
 
# 在 [0,1]×[0,1] 正方形内随机投点
x = np.random.uniform(0, 1, n_samples)
y = np.random.uniform(0, 1, n_samples)
 
# 计算落在单位圆内的比例
inside_circle = (x**2 + y**2) <= 1
pi_estimate = 4 * inside_circle.sum() / n_samples
 
print(f"π 的蒙特卡洛估计: {pi_estimate:.6f}")
print(f"真实 π 值: {np.pi:.6f}")
print(f"误差: {abs(pi_estimate - np.pi):.6f}")

为什么这能估算π?因为单位圆面积是 ,落在圆内的概率也是 ,用大数定律,频率趋向概率。

强大数定律:样本均值几乎必然(almost surely)收敛到期望。比弱大数定律更强——不是”依概率收敛”,而是”几乎所有实现都收敛”。

3.2 中心极限定理——概率论最神奇的定理

中心极限定理(CLT):

是独立同分布的随机变量,,则:

其中 是标准正态分布的CDF。

用代码直观理解CLT

fig, axes = plt.subplots(2, 3, figsize=(15, 10))
 
# 不同的原始分布
distributions = {
    '均匀分布': lambda n: np.random.uniform(0, 1, n),
    '二项分布': lambda n: np.random.binomial(10, 0.5, n),
    '泊松分布': lambda n: np.random.poisson(5, n),
    '指数分布': lambda n: np.random.exponential(1, n),
    '离散分布 [0,1,3]': lambda n: np.random.choice([0, 1, 3], n, p=[0.2, 0.5, 0.3]),
    '柯西分布': lambda n: np.random.standard_cauchy(n),
}
 
for ax, (name, dist_func) in zip(axes.flat, distributions.items()):
    sample_means = []
    n_experiments = 1000
    sample_size = 100
    
    for _ in range(n_experiments):
        sample = dist_func(sample_size)
        sample_means.append(np.mean(sample))
    
    # 标准化
    sample_means = np.array(sample_means)
    # 假设知道真实均值(对某些分布用中位数估计)
    if name == '柯西分布':
        mu_estimate = np.median(sample_means)
    else:
        mu_estimate = np.mean(sample_means)
    std_estimate = np.std(sample_means)
    standardized = (sample_means - mu_estimate) / (std_estimate / np.sqrt(sample_size))
    
    ax.hist(standardized, bins=50, density=True, alpha=0.7, label='样本均值的标准化')
    x = np.linspace(-4, 4, 100)
    ax.plot(x, stats.norm.pdf(x), 'r-', lw=2, label='标准正态分布')
    ax.set_title(f'{name}\n(样本量={sample_size})')
    ax.legend()
    ax.set_xlim(-4, 4)
 
plt.suptitle('中心极限定理:无论原始分布是什么,样本均值都趋向正态分布', fontsize=14)
plt.tight_layout()
plt.show()

CLT为什么重要?

  1. 解释了正态分布的普遍性:大量微小独立因素叠加的结果就是正态分布
  2. 统计推断的理论基础:置信区间、假设检验都依赖正态性假设
  3. 近似计算:即使不知道原始分布,也可以用正态分布近似样本均值的分布

3.3 正态分布——统计学之王

正态分布(高斯分布)

# 绘制正态分布
x = np.linspace(-5, 5, 1000)
 
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
 
# 不同均值
ax1 = axes[0]
for mu in [-1, 0, 1]:
    y = stats.norm.pdf(x, mu, 1)
    ax1.plot(x, y, label=f'μ={mu}, σ=1', lw=2)
ax1.set_title('不同均值,相同方差')
ax1.legend()
ax1.grid(True, alpha=0.3)
 
# 不同方差
ax2 = axes[1]
for sigma in [0.5, 1, 2]:
    y = stats.norm.pdf(x, 0, sigma)
    ax2.plot(x, y, label=f'μ=0, σ={sigma}', lw=2)
ax2.set_title('相同均值,不同方差')
ax2.legend()
ax2.grid(True, alpha=0.3)
 
plt.show()

68-95-99.7法则

范围包含概率
约 68.3%
约 95.5%
约 99.7%
# 验证68-95-99.7法则
samples = np.random.randn(1000000)
 
within_1sigma = (samples > -1) & (samples < 1)
within_2sigma = (samples > -2) & (samples < 2)
within_3sigma = (samples > -3) & (samples < 3)
 
print(f"在 μ±1σ 范围内: {within_1sigma.mean():.4f} (理论: 0.6827)")
print(f"在 μ±2σ 范围内: {within_2sigma.mean():.4f} (理论: 0.9545)")
print(f"在 μ±3σ 范围内: {within_3sigma.mean():.4f} (理论: 0.9973)")

四、随机变量与概率分布

4.1 常用离散分布速查

分布记号PMF适用场景sklearn/PyTorch
伯努利抛一次硬币
二项n次实验的成功次数scipy.stats.binom
几何首次成功需要的次数scipy.stats.geom
泊松稀有事件计数scipy.stats.poisson

泊松分布的代码示例

# 泊松分布:描述稀有事件在固定时间/空间内的发生次数
# 例子:一个网站每小时平均收到50次请求
 
lambda_param = 50  # 平均每小时50次请求
 
# 计算各种请求次数的概率
k_values = np.arange(30, 71)
probs = stats.poisson.pmf(k_values, lambda_param)
 
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.bar(k_values, probs)
plt.xlabel('请求次数 k')
plt.ylabel('概率 P(X=k)')
plt.title(f'泊松分布 Poisson(λ={lambda_param})')
 
# 累积分布
plt.subplot(1, 2, 2)
cdf = stats.poisson.cdf(k_values, lambda_param)
plt.plot(k_values, cdf)
plt.xlabel('请求次数 k')
plt.ylabel('累积概率 P(X≤k)')
plt.title('泊松分布的CDF')
plt.tight_layout()
plt.show()
 
# 常见计算
print(f"P(X=50) = {stats.poisson.pmf(50, lambda_param):.4f}")
print(f"P(X≤40) = {stats.poisson.cdf(40, lambda_param):.4f}")
print(f"P(X≥60) = {1 - stats.poisson.cdf(59, lambda_param):.4f}")

4.2 常用连续分布速查

分布记号PDF适用场景
均匀没有任何先验偏好
正态钟形曲线大多数连续测量值
指数等待时间、衰减
Gamma正态的共轭先验
Beta[0,1]区间上的概率
t分布重尾正态小样本估计

指数分布——无记忆性的等待时间

# 指数分布:λ 是率参数(平均等待时间 = 1/λ)
lambda_param = 2  # 平均每分钟来2个顾客
 
# PDF
x = np.linspace(0, 4, 1000)
pdf = stats.expon.pdf(x, scale=1/lambda_param)  # scale = 1/λ
 
plt.figure(figsize=(12, 5))
 
plt.subplot(1, 2, 1)
plt.plot(x, pdf, 'b-', lw=2)
plt.xlabel('时间 x (分钟)')
plt.ylabel('概率密度 f(x)')
plt.title(f'指数分布 Exp(λ={lambda_param})')
plt.grid(True, alpha=0.3)
 
# 验证无记忆性
plt.subplot(1, 2, 2)
# P(T > s + t | T > s) = P(T > t)
t = 0.5
s_values = [0, 0.5, 1.0, 1.5]
for s in s_values:
    # 条件概率 P(T > s+t | T > s) = P(T > s+t) / P(T > s)
    # = exp(-λ(s+t)) / exp(-λs) = exp(-λt)
    conditional_prob = np.exp(-lambda_param * t)
    print(f"已等待 {s} 分钟,再等 {t} 分钟总时间超过 {s+t} 分钟的条件概率: {conditional_prob:.4f}")
 
plt.text(0.5, 0.8, '无记忆性:无论已经等了多久\n再等待t时间的概率都一样', 
         transform=plt.gca().transAxes, fontsize=12,
         bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
plt.show()

4.3 概率分布速查表:常用分布在sklearn/PyTorch中

分布NumPySciPyPyTorch用途
正态 np.random.normalstats.normtorch.distributions.Normal回归、VAE
均匀 np.random.uniformstats.uniformtorch.distributions.Uniform采样初始化
伯努利 np.random.binomial(1,p)stats.bernoullitorch.distributions.Bernoulli二分类
类别np.random.choicetorch.distributions.Categorical多分类
Betascipy.stats.betastats.betatorch.distributions.Beta概率参数
指数np.random.exponentialstats.expotorch.distributions.Exponential率参数
import torch
 
# PyTorch 分布示例
# 定义一个正态分布
loc = torch.tensor([0.0, 0.0])
scale = torch.tensor([1.0, 0.5])
normal_dist = torch.distributions.Normal(loc, scale)
 
# 采样
samples = normal_dist.sample((1000,))  # shape: (1000, 2)
print(f"采样形状: {samples.shape}")
 
# 计算对数概率
x = torch.tensor([0.5, 0.5])
log_prob = normal_dist.log_prob(x)
print(f"log P(x): {log_prob}")
 
# VAE中重参数化采样的典型用法
def reparameterized_sample(mu, log_var):
    """重参数化技巧:让采样操作可导"""
    std = torch.exp(0.5 * log_var)
    eps = torch.randn_like(std)  # 标准正态采样
    return mu + eps * std

五、数字特征:期望、方差、协方差

5.1 期望值——概率加权的平均值

离散情形

连续情形

期望的本质:用概率加权的”平均”值。如果重复实验无数次,长期平均就是期望。

# 掷骰子的期望值
# 方法1:理论计算
X_values = np.array([1, 2, 3, 4, 5, 6])
probabilities = np.array([1/6] * 6)
E_X = np.sum(X_values * probabilities)
print(f"理论期望: {E_X}")  # 应该是 3.5
 
# 方法2:蒙特卡洛
rolls = np.random.randint(1, 7, size=1000000)
E_X_estimate = np.mean(rolls)
print(f"蒙特卡洛估计: {E_X_estimate:.4f}")

期望的性质

  1. 线性性
  2. 对独立变量:
# 验证线性性
np.random.seed(42)
X = np.random.randn(1000)
Y = np.random.randn(1000)
a, b = 2, -3
 
lhs = np.mean(a * X + b * Y)  # E[aX + bY]
rhs = a * np.mean(X) + b * np.mean(Y)  # aE[X] + bE[Y]
print(f"E[aX + bY] = {lhs:.4f}")
print(f"aE[X] + bE[Y] = {rhs:.4f}")
print(f"线性性成立: {np.isclose(lhs, rhs)}")

5.2 方差与标准差——衡量”散”的程度

方差

标准差,与原变量量纲相同

# 计算方差
X = np.array([1, 2, 3, 4, 5, 6])
 
# 方法1:定义公式
mean_X = np.mean(X)
var_X = np.mean((X - mean_X)**2)
print(f"定义公式: Var(X) = {var_X:.4f}")
 
# 方法2:简化公式 E[X²] - (E[X])²
var_X_simple = np.mean(X**2) - np.mean(X)**2
print(f"简化公式: Var(X) = {var_X_simple:.4f}")
 
# 方法3:NumPy内置
var_X_numpy = np.var(X)  # 默认ddof=0(总体方差)
var_X_sample = np.var(X, ddof=1)  # 样本方差
print(f"NumPy 总体方差: {var_X_numpy:.4f}")
print(f"NumPy 样本方差: {var_X_sample:.4f}")

注意:NumPy默认计算的是总体方差(除以 ),统计学中通常用样本方差(除以 ,ddof=1)。样本方差是对总体方差的无偏估计。

方差的性质

  • 对独立变量:
  • 常数不贡献方差:
# 验证:独立变量方差的叠加性
np.random.seed(42)
X = np.random.randn(10000) * 2 + 1  # N(1, 4)
Y = np.random.randn(10000) * 3 - 2   # N(-2, 9)
 
Z = X + Y
 
print(f"Var(X) = {np.var(X):.4f} (理论: 4)")
print(f"Var(Y) = {np.var(Y):.4f} (理论: 9)")
print(f"Var(X+Y) = {np.var(Z):.4f} (理论: 13)")

5.3 协方差与相关系数——衡量两个变量的”同涨同跌”

协方差

相关系数(Pearson相关系数):

# 生成相关数据
np.random.seed(42)
n = 1000
 
# 正相关
X_pos = np.random.randn(n)
Y_pos = X_pos + 0.5 * np.random.randn(n)
 
# 负相关
X_neg = np.random.randn(n)
Y_neg = -0.7 * X_neg + 0.5 * np.random.randn(n)
 
# 不相关
X_ind = np.random.randn(n)
Y_ind = np.random.randn(n)
 
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
 
for ax, (x, y, title) in zip(axes, [
    (X_pos, Y_pos, f'正相关 ρ ≈ {np.corrcoef(x, y)[0,1]:.2f}'),
    (X_neg, Y_neg, f'负相关 ρ ≈ {np.corrcoef(x, y)[0,1]:.2f}'),
    (X_ind, Y_ind, f'不相关 ρ ≈ {np.corrcoef(x, y)[0,1]:.2f}')
]):
    ax.scatter(x, y, alpha=0.5, s=10)
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_title(title)
    ax.grid(True, alpha=0.3)
 
plt.tight_layout()
plt.show()

协方差矩阵

对于多维变量

# 协方差矩阵
np.random.seed(42)
n = 1000
 
# 生成二元正态分布数据
mean = [0, 0]
cov = [[1, 0.7], [0.7, 1]]  # 协方差矩阵
X = np.random.multivariate_normal(mean, cov, n)
 
# 计算协方差矩阵
cov_matrix = np.cov(X.T)
print("协方差矩阵:")
print(cov_matrix)
 
# 可视化
plt.scatter(X[:, 0], X[:, 1], alpha=0.5, s=10)
plt.xlabel('X₁')
plt.ylabel('X₂')
plt.title(f'二元正态分布 (ρ = {cov_matrix[0,1]/np.sqrt(cov_matrix[0,0]*cov_matrix[1,1]):.2f})')
 
# 绘制置信椭圆
from matplotlib.patches import Ellipse
def confidence_ellipse(ax, mean, cov, n_std=2.0, **kwargs):
    """绘制协方差椭圆的置信区间"""
    pearson = cov[0, 1] / np.sqrt(cov[0, 0] * cov[1, 1])
    ell_radius_x = np.sqrt(1 + pearson)
    ell_radius_y = np.sqrt(1 - pearson)
    ellipse = Ellipse((0, 0), width=ell_radius_x * 2, height=ell_radius_y * 2, **kwargs)
    
    scale_x = np.sqrt(cov[0, 0]) * n_std
    mean_x, mean_y = mean
    
    transf = (plt.matplotlib.transforms.Affine2D()
              .rotate_deg(45)
              .scale(scale_x, np.sqrt(cov[1, 1]) * n_std)
              .translate(mean_x, mean_y))
    
    ellipse.set_transform(transf + ax.transData)
    return ax.add_patch(ellipse)
 
confidence_ellipse(plt.gca(), [0, 0], cov_matrix, n_std=1, 
                   edgecolor='red', linestyle='--', fill=False, linewidth=2, label='1σ')
confidence_ellipse(plt.gca(), [0, 0], cov_matrix, n_std=2, 
                   edgecolor='blue', linestyle='--', fill=False, linewidth=2, label='2σ')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

警告:相关不等于因果! 只说明两个变量”同涨同跌”,不意味着X导致了Y,或者Y导致了X。


六、最大似然估计MLE——从概率论到参数学习

6.1 MLE的核心思想

最大似然估计(Maximum Likelihood Estimation)的思想很简单:找到让观测数据出现的概率(似然)最大的参数值

换句话说:“既然这批数据已经出现了,那最合理的参数应该是使这批数据出现概率最大的那个”。

似然函数

通常我们最大化对数似然(因为乘积变加法,好处理):

6.2 MLE的代码实战

例1:估计硬币正面概率

# 观测数据:抛10次硬币,7次正面
n = 10
k = 7  # 正面次数
 
# 似然函数 L(p) = C(n,k) * p^k * (1-p)^(n-k)
# 取对数后:ℓ(ρ) = log C + k*log(p) + (n-k)*log(1-p)
 
p_values = np.linspace(0.01, 0.99, 100)
log_likelihood = k * np.log(p_values) + (n - k) * np.log(1 - p_values)
 
# 找到MLE
p_mle = k / n  # 对二项分布,MLE就是样本均值
 
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.plot(p_values, log_likelihood, 'b-', lw=2)
plt.axvline(p_mle, color='r', linestyle='--', label=f'MLE p̂ = {p_mle}')
plt.xlabel('p')
plt.ylabel('对数似然 ℓ(p)')
plt.title('对数似然函数')
plt.legend()
plt.grid(True, alpha=0.3)
 
plt.subplot(1, 2, 2)
likelihood = p_values**k * (1 - p_values)**(n - k)
plt.plot(p_values, likelihood, 'g-', lw=2)
plt.axvline(p_mle, color='r', linestyle='--', label=f'MLE p̂ = {p_mle}')
plt.xlabel('p')
plt.ylabel('似然 L(p)')
plt.title('似然函数')
plt.legend()
plt.grid(True, alpha=0.3)
 
plt.tight_layout()
plt.show()
 
print(f"最大似然估计: p̂ = {p_mle}")

例2:估计正态分布参数

# 观测数据:从正态分布中采样
np.random.seed(42)
true_mu, true_sigma = 5, 2
data = np.random.normal(true_mu, true_sigma, 100)
 
# 对数似然函数
def log_likelihood_normal(data, mu, sigma):
    n = len(data)
    return -n/2 * np.log(2*np.pi) - n*np.log(sigma) - np.sum((data - mu)**2) / (2*sigma**2)
 
# 可视化对数似然
mu_values = np.linspace(3, 7, 100)
sigma_values = np.linspace(1, 4, 100)
LL = np.zeros((len(sigma_values), len(mu_values)))
 
for i, sigma in enumerate(sigma_values):
    for j, mu in enumerate(mu_values):
        LL[i, j] = log_likelihood_normal(data, mu, sigma)
 
# 绘制等高线图
plt.figure(figsize=(10, 8))
contour = plt.contour(mu_values, sigma_values, LL, levels=20)
plt.clabel(contour, inline=True, fontsize=8)
 
# 标记真实值和MLE
plt.scatter([true_mu], [true_sigma], c='red', s=200, marker='*', label=f'真实值: μ={true_mu}, σ={true_sigma}')
mu_mle = np.mean(data)
sigma_mle = np.std(data, ddof=1)
plt.scatter([mu_mle], [sigma_mle], c='blue', s=200, marker='x', label=f'MLE: μ̂={mu_mle:.2f}, σ̂={sigma_mle:.2f}')
 
plt.xlabel('μ (均值)')
plt.ylabel('σ (标准差)')
plt.title('正态分布对数似然等高线图')
plt.legend()
plt.colorbar(contour, label='对数似然')
plt.show()
 
print(f"真实参数: μ={true_mu}, σ={true_sigma}")
print(f"MLE估计: μ̂={mu_mle:.4f}, σ̂={sigma_mle:.4f}")

6.3 MLE在机器学习中的角色

逻辑回归的MLE

逻辑回归本质上是在做MLE。给定输入 ,输出 ,假设:

似然函数:

最大化似然等价于最小化交叉熵损失

所以,训练模型 = MLE = 最小化损失函数,它们是同一回事!


七、蒙特卡洛方法实战——用随机采样估算一切

7.1 蒙特卡洛方法的基本思想

蒙特卡洛方法的核心思想是:用随机采样的均值来估计期望值

7.2 蒙特卡洛积分

# 蒙特卡洛积分:计算 π
np.random.seed(42)
N = 1000000
 
# 方法:在单位正方形内随机投点
x = np.random.uniform(-1, 1, N)
y = np.random.uniform(-1, 1, N)
 
# 计算落在单位圆内的比例
inside = (x**2 + y**2) <= 1
pi_estimate = 4 * inside.sum() / N
 
print(f"蒙特卡洛估计: π ≈ {pi_estimate:.6f}")
print(f"真实值: π = {np.pi:.6f}")
print(f"绝对误差: {abs(pi_estimate - np.pi):.6f}")
 
# 收敛速度:画出估计值随样本量的变化
sample_sizes = [10, 100, 1000, 10000, 100000, 1000000]
estimates = []
 
for n in sample_sizes:
    x = np.random.uniform(-1, 1, n)
    y = np.random.uniform(-1, 1, n)
    inside = (x**2 + y**2) <= 1
    estimates.append(4 * inside.sum() / n)
 
plt.figure(figsize=(10, 5))
plt.semilogx(sample_sizes, estimates, 'bo-', label='蒙特卡洛估计')
plt.axhline(np.pi, color='r', linestyle='--', label=f'真实值 π = {np.pi:.6f}')
plt.xlabel('样本量 N (对数尺度)')
plt.ylabel('π 的估计值')
plt.title('蒙特卡洛方法的收敛性')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

7.3 重要性采样

当直接采样困难时,重要性采样(Importance Sampling)引入一个容易采样的分布

其中 是重要性权重。

# 重要性采样示例:估计 E[exp(-X)] 其中 X ~ N(0,1)
# 这个积分没有解析解
 
from scipy import stats
 
np.random.seed(42)
 
# 目标分布 p(x) 和提议分布 q(x)
p = stats.norm(0, 1)  # 标准正态
q = stats.norm(2, 1.5)  # 选择一个偏移的正态分布作为提议
 
N = 100000
x_q = q.rvs(N)  # 从 q 采样
 
# 计算重要性权重
log_weights = p.logpdf(x_q) - q.logpdf(x_q)
weights = np.exp(log_weights)
weights = weights / weights.sum()  # 归一化
 
# 估计 E[exp(-X)]
f = np.exp(-x_q)  # f(x) = exp(-x)
estimate = np.sum(weights * f)
 
# 直接蒙特卡洛(从 p 采样)作为对比
x_p = p.rvs(N)
direct_estimate = np.mean(np.exp(-x_p))
 
print(f"重要性采样估计: {estimate:.6f}")
print(f"直接蒙特卡洛估计: {direct_estimate:.6f}")
 
# 理论值(通过数值积分)
from scipy import integrate
true_value, _ = integrate.quad(lambda x: np.exp(-x) * p.pdf(x), -np.inf, np.inf)
print(f"理论值: {true_value:.6f}")

7.4 马尔可夫链蒙特卡洛(MCMC)

当高维积分难以计算时(如贝叶斯后验),MCMC是常用工具。

# Metropolis-Hastings 算法简明实现
def metropolis_hastings(target_log_pdf, proposal_std=1, n_samples=10000, burn_in=1000):
    """
    Metropolis-Hastings MCMC采样器
    
    参数:
        target_log_pdf: 目标分布的对数概率密度函数
        proposal_std: 提议分布(正态)的标准差
        n_samples: 样本数量
        burn_in: 预热期(丢弃前burn_in个样本)
    """
    samples = []
    x_current = 0  # 初始值
    
    for i in range(n_samples + burn_in):
        # 提议
        x_proposed = np.random.normal(x_current, proposal_std)
        
        # 计算接受概率
        log_alpha = target_log_pdf(x_proposed) - target_log_pdf(x_current)
        
        #  Metropolis 接受准则
        if np.log(np.random.rand()) < log_alpha:
            x_current = x_proposed
        
        # 丢弃预热期,保存剩余样本
        if i >= burn_in:
            samples.append(x_current)
    
    return np.array(samples)
 
# 示例:从 Beta(2, 5) 分布采样
def beta_log_pdf(x, alpha=2, beta=5):
    if x <= 0 or x >= 1:
        return -np.inf
    return (alpha - 1) * np.log(x) + (beta - 1) * np.log(1 - x)
 
samples = metropolis_hastings(beta_log_pdf, proposal_std=0.5, n_samples=50000, burn_in=5000)
 
# 可视化
x = np.linspace(0, 1, 1000)
true_pdf = stats.beta.pdf(x, 2, 5)
 
plt.figure(figsize=(12, 5))
 
plt.subplot(1, 2, 1)
plt.hist(samples, bins=50, density=True, alpha=0.7, label='MCMC样本')
plt.plot(x, true_pdf, 'r-', lw=2, label='真实密度 Beta(2,5)')
plt.xlabel('x')
plt.ylabel('概率密度')
plt.title('Metropolis-Hastings 采样效果')
plt.legend()
plt.grid(True, alpha=0.3)
 
plt.subplot(1, 2, 2)
plt.plot(samples[:500], 'b-', lw=0.5, alpha=0.7)
plt.xlabel('迭代次数')
plt.ylabel('x')
plt.title('马尔可夫链轨迹(前500步)')
plt.grid(True, alpha=0.3)
 
plt.tight_layout()
plt.show()
 
# 检查自相关(判断混合效果)
from scipy import signal
def autocorrelation(x, lag):
    return np.corrcoef(x[:-lag], x[lag:])[0, 1]
 
lags = np.arange(1, 100)
acs = [autocorrelation(samples, lag) for lag in lags]
 
plt.figure(figsize=(10, 4))
plt.plot(lags, acs)
plt.xlabel('滞后 (Lag)')
plt.ylabel('自相关')
plt.title('样本自相关函数')
plt.axhline(0, color='k', linestyle='--')
plt.grid(True, alpha=0.3)
plt.show()

八、新手易错点:概率论中的直觉陷阱

8.1 独立 ≠ 不相关

陷阱:相关(协方差为零)不等于独立!

# 经典反例:X ~ Uniform(-1, 1), Y = X²
# Cov(X, Y) = 0 但 X 和 Y 明显不独立
 
np.random.seed(42)
X = np.random.uniform(-1, 1, 10000)
Y = X**2
 
cov = np.cov(X, Y)[0, 1]
corr = np.corrcoef(X, Y)[0, 1]
 
print(f"协方差: {cov:.6f}")
print(f"相关系数: {corr:.6f}")
print(f"Cov = 0 但 X 和 Y 独立吗?{'是' if cov == 0 else '否'}(明显不是!)")
 
# 验证:P(Y > 0.5 | X > 0) ≠ P(Y > 0.5)
p_y_given_x = np.mean(Y[X > 0] > 0.5)
p_y = np.mean(Y > 0.5)
print(f"P(Y > 0.5) = {p_y:.4f}")
print(f"P(Y > 0.5 | X > 0) = {p_y_given_x:.4f}")
print("说明 Y 和 X 条件独立?", "是" if np.isclose(p_y, p_y_given_x) else "否")

8.2 赌徒谬误

陷阱:认为随机事件会”自我修正”,之前发生太多次”正面”会导致接下来更可能出”反面”。

但硬币没有记忆!每次抛掷都是独立的。

# 模拟10000次抛硬币,连续出现10次正面后,第11次正面还是反面的概率?
np.random.seed(42)
 
# 理论上,每次抛掷正面概率都是0.5
# 但人的直觉会认为第11次更可能是反面
 
# 模拟:找到连续10次正面的序列,看之后第11次是什么
n_simulations = 100000
next_flip_after_10_heads = []
 
for _ in range(n_simulations):
    flips = np.random.randint(0, 2, 25)
    for i in range(len(flips) - 10):
        if np.all(flips[i:i+10] == 1):
            next_flip_after_10_heads.append(flips[i+10])
            break
 
next_flip = np.array(next_flip_after_10_heads)
print(f"连续10次正面后,第11次正面的频率: {np.mean(next_flip):.4f}")
print("直觉会认为应该小于0.5,但实际应该接近0.5!")

8.3 条件概率的顺序效应

陷阱。混淆条件概率的前后顺序是最常见的错误之一。

# 再看那个体检的例子
# P(患病|阳性) vs P(阳性|患病)
 
# P(阳性|患病) = 0.99 (检测对病人的准确率)
// P(患病|阳性) ≠ 0.99!
 
P_disease = 0.01
P_positive_given_disease = 0.99
P_positive_given_healthy = 0.05
 
P_disease_given_positive = (P_positive_given_disease * P_disease) / (
    P_positive_given_disease * P_disease + P_positive_given_healthy * (1 - P_disease))
 
print(f"P(阳性|患病) = {P_positive_given_disease}")
print(f"P(患病|阳性) = {P_disease_given_positive:.4f}")
print("\n这两个概率差别巨大!特别是当疾病很罕见时。")

8.4 期望的线性 vs 方差的非线性

陷阱:对独立变量, 成立,但 要求X和Y独立。

# 构造一个反例:Cov(X,Y) ≠ 0
np.random.seed(42)
X = np.random.randn(10000)
Y = 2 * X + np.random.randn(10000) * 0.1  # Y 与 X 相关
 
print(f"Var(X) = {np.var(X):.4f}")
print(f"Var(Y) = {np.var(Y):.4f}")
print(f"Var(X + Y) = {np.var(X + Y):.4f}")
print(f"Var(X) + Var(Y) = {np.var(X) + np.var(Y):.4f}")
print("\nVar(X+Y) ≠ Var(X) + Var(Y) 因为 X 和 Y 不独立!")

8.5 大数定律的收敛速度

陷阱:大数定律说”样本均值趋向期望”,但没说需要多少样本才能接近!

# 演示:不同样本量下,样本均值的波动
np.random.seed(42)
sample_means = []
 
for n in [10, 50, 100, 500, 1000, 5000, 10000, 50000, 100000]:
    samples = np.random.uniform(0, 1, n)
    sample_means.append(np.mean(samples))
 
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.semilogx([10, 50, 100, 500, 1000, 5000, 10000, 50000, 100000], 
             sample_means, 'bo-')
plt.axhline(0.5, color='r', linestyle='--', label='真实期望 0.5')
plt.xlabel('样本量 (对数)')
plt.ylabel('样本均值')
plt.title('样本量 vs 样本均值')
plt.legend()
plt.grid(True, alpha=0.3)
 
# 收敛区间
plt.subplot(1, 2, 2)
ns = np.array([10, 50, 100, 500, 1000, 5000, 10000, 50000, 100000])
stds = 1 / np.sqrt(ns)  # 样本均值的标准误
plt.fill_between(ns, 0.5 - 1.96*stds, 0.5 + 1.96*stds, alpha=0.3, label='95%置信区间')
plt.semilogx(ns, sample_means, 'bo-', label='样本均值')
plt.axhline(0.5, color='r', linestyle='--', label='真实期望')
plt.xlabel('样本量')
plt.ylabel('样本均值')
plt.title('95%置信区间随样本量变化')
plt.legend()
plt.grid(True, alpha=0.3)
 
plt.tight_layout()
plt.show()
 
print("结论:要达到0.01的精度,需要至少 n ≈ 1/0.01² = 10000 个样本!")

九、概率分布速查表

9.1 常用分布一览

分布符号参数PMF/PDF期望方差应用场景
伯努利单次二元实验
二项n次实验成功数
几何首次成功次数
泊松稀有事件计数
均匀无先验偏好
正态钟形曲线测量误差、CLT
指数等待时间
Gamma正态的共轭先验
Beta概率参数
t分布 (自由度)重尾曲线 (若 ) (若 )小样本推断
卡方 (自由度)方差估计

9.2 共轭先验对照表

似然分布共轭先验后验更新规则
Bernoulli()Beta(),
Binomial()Beta(),
Poisson()Gamma(),
Normal()(已知)Normal()
Normal()(已知)Inverse-Gamma()
Multinomial()Dirichlet()

十、概率论在机器学习中的高级应用

10.1 变分推断

变分推断(Variational Inference)将后验分布的近似问题转化为优化问题:

"""
变分推断简明示例:用平均场变分近似估计硬币正面概率的后验
 
目标:用简单的分布 q(p) 近似真实后验 p(p|X)
 
平均场变分族:q(p) = Beta(α_q, β_q)
 
优化目标:最大化 ELBO = E_q[log p(X|p)] + E_q[log p(p)] - E_q[log q(p)]
"""
 
def elbo(alpha_q, beta_q, n_heads, n_flips, alpha_prior=1, beta_prior=1):
    """
    计算 ELBO (Evidence Lower Bound)
    """
    # 更新后的参数
    alpha_post = alpha_prior + n_heads
    beta_post = beta_prior + (n_flips - n_heads)
    
    # 使用 scipy 的 beta 分布
    q = stats.beta(alpha_q, beta_q)
    p_prior = stats.beta(alpha_prior, beta_prior)
    p_post = stats.beta(alpha_post, beta_post)
    
    # 数值积分计算期望
    x = np.linspace(0.001, 0.999, 1000)
    
    # E_q[log p(X|p)] - 使用泊松二项分布的近似
    # log p(X|p) = log C + k*log(p) + (n-k)*log(1-p)
    E_log_likelihood = np.sum(q.logpdf(x) * (n_heads * np.log(x) + (n_flips - n_heads) * np.log(1 - x)))
    
    # E_q[log p(p)] - 先验
    E_log_prior = np.sum(q.logpdf(x) * p_prior.logpdf(x))
    
    # -E_q[log q(p)]
    neg_entropy = -np.sum(q.logpdf(x) * q.logpdf(x))
    
    # 近似计算
    from scipy.special import gammaln, digamma
    
    # 使用均值场近似的解析形式
    E_log_likelihood_approx = (
        (n_heads - alpha_q) * (digamma(alpha_q) - np.log(alpha_q + beta_q)) +
        (n_flips - n_heads - beta_q) * (digamma(beta_q) - np.log(alpha_q + beta_q))
    )
    
    E_log_prior_approx = (
        (alpha_prior - alpha_q) * (digamma(alpha_q) - np.log(alpha_q + beta_q)) +
        (beta_prior - beta_q) * (digamma(beta_q) - np.log(alpha_q + beta_q)) +
        gammaln(alpha_q + beta_q) - gammaln(alpha_q) - gammaln(beta_q) +
        (alpha_q - 1) * (digamma(alpha_q) - np.log(alpha_q + beta_q)) +
        (beta_q - 1) * (digamma(beta_q) - np.log(alpha_q + beta_q))
    )
    
    return E_log_likelihood_approx + E_log_prior_approx + (
        gammaln(alpha_q + beta_q) - gammaln(alpha_q) - gammaln(beta_q) +
        (alpha_q - 1) * digamma(alpha_q) +
        (beta_q - 1) * digamma(beta_q) -
        (alpha_q + beta_q - 2) * digamma(alpha_q + beta_q)
    )
 
# 观测数据
n_flips = 100
n_heads = 70
 
# 优化找到最优的 q 参数
from scipy.optimize import minimize
 
def neg_elbo(params):
    alpha_q, beta_q = params[0], params[1]
    if alpha_q <= 0 or beta_q <= 0:
        return 1e10
    return -elbo(alpha_q, beta_q, n_heads, n_flips)
 
result = minimize(neg_elbo, x0=[2, 2], method='L-BFGS-B', 
                  bounds=[(0.01, 100), (0.01, 100)])
 
alpha_q_opt, beta_q_opt = result.x
print(f"最优变分参数: α_q = {alpha_q_opt:.2f}, β_q = {beta_q_opt:.2f}")
 
# 真实后验
alpha_post = 1 + n_heads
beta_post = 1 + (n_flips - n_heads)
print(f"真实后验: α = {alpha_post}, β = {beta_post}")
 
# 可视化
x = np.linspace(0.01, 0.99, 1000)
true_posterior = stats.beta.pdf(x, alpha_post, beta_post)
variational_posterior = stats.beta.pdf(x, alpha_q_opt, beta_q_opt)
 
plt.figure(figsize=(10, 5))
plt.plot(x, true_posterior, 'b-', lw=2, label='真实后验')
plt.plot(x, variational_posterior, 'r--', lw=2, label=f'变分近似 q(p)')
plt.xlabel('p (正面概率)')
plt.ylabel('概率密度')
plt.title('变分推断:近似后验分布')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

10.2 高斯混合模型(GMM)

"""
高斯混合模型:用EM算法拟合
"""
from sklearn.mixture import GaussianMixture
 
# 生成模拟数据:两个簇
np.random.seed(42)
cluster1 = np.random.multivariate_normal([0, 0], [[1, 0.5], [0.5, 1]], 300)
cluster2 = np.random.multivariate_normal([5, 5], [[1, -0.3], [-0.3, 1]], 200)
X = np.vstack([cluster1, cluster2])
 
# 用GMM拟合
gmm = GaussianMixture(n_components=2, random_state=42)
gmm.fit(X)
 
print(f"混合权重: {gmm.weights_}")
print(f"均值:\n{gmm.means_}")
print(f"协方差矩阵:\n{gmm.covariances_}")
 
# 可视化
plt.figure(figsize=(12, 5))
 
plt.subplot(1, 2, 1)
plt.scatter(X[:, 0], X[:, 1], c=gmm.predict(X), cmap='viridis', alpha=0.5, s=10)
plt.xlabel('X₁')
plt.ylabel('X₂')
plt.title('GMM 聚类结果')
 
plt.subplot(1, 2, 2)
x1 = np.linspace(-3, 8, 200)
x2 = np.linspace(-3, 8, 200)
X1, X2 = np.meshgrid(x1, x2)
pos = np.dstack((X1, X2))
 
# 计算混合概率密度
Z = np.exp(gmm.score_samples(pos))  # 返回 log-likelihood,需要 exp
plt.contourf(X1, X2, Z, levels=20, cmap='viridis', alpha=0.8)
plt.scatter(X[:, 0], X[:, 1], c='white', alpha=0.3, s=5)
plt.colorbar(label='概率密度')
plt.xlabel('X₁')
plt.ylabel('X₂')
plt.title('GMM 概率密度等高线')
 
plt.tight_layout()
plt.show()

10.3 朴素贝叶斯分类器

"""
朴素贝叶斯分类器实战:垃圾邮件分类
"""
from sklearn.naive_bayes import MultinomialNB, GaussianNB
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
 
# 模拟邮件数据
emails = [
    "免费 赢取 奖金 点击 这里",
    "亲爱的 用户 恭喜 您 中奖",
    "会议 安排 在 明天 三点",
    "项目 进度 报告 请查收",
    "限时 优惠 立即 购买",
    "周五 讨论 技术方案",
    "账户 安全 问题 需要 处理",
    "新产品 发布 会 邀请",
    "赌博 平台 稳定 收益",
    "季度 财务 总结 会议",
] * 50  # 重复以增加样本量
 
labels = [1, 1, 0, 0, 1, 0, 0, 0, 1, 0] * 50  # 1=垃圾邮件, 0=正常邮件
 
# 文本向量化
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(emails)
y = np.array(labels)
 
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
 
# 训练朴素贝叶斯分类器
nb = MultinomialNB()
nb.fit(X_train, y_train)
 
# 预测
y_pred = nb.predict(X_test)
 
print("分类报告:")
print(classification_report(y_test, y_pred, target_names=['正常邮件', '垃圾邮件']))
 
# 预测新邮件
new_email = "免费 赢取 奖金"
new_X = vectorizer.transform([new_email])
pred = nb.predict(new_X)
prob = nb.predict_proba(new_X)
 
print(f"\n新邮件: '{new_email}'")
print(f"预测结果: {'垃圾邮件' if pred[0] == 1 else '正常邮件'}")
print(f"预测概率: 正常={prob[0][0]:.4f}, 垃圾={prob[0][1]:.4f}")

十一、概率论基础公式速查

11.1 基本公式

公式表达式
条件概率
乘法公式
全概率公式
贝叶斯定理

11.2 期望与方差公式

公式表达式
期望线性性
独立变量乘积期望(独立时)
方差定义
方差简化
独立变量方差和(独立时)
协方差

11.3 常用不等式

不等式表达式
Markov
Chebyshev
Hoeffding$P(
Chernoff

十二、延伸阅读

概率论是一座博大精深的学科,以上内容只是冰山一角。以下是进一步学习的推荐路径:

入门进阶

  • 深度学习花书第3章:概率与信息论
  • 《概率论与数理统计》陈希孺
  • 《All of Statistics》Larry Wasserman

贝叶斯方法

  • 《Bayesian Data Analysis》Gelman et al.
  • 《Statistical Rethinking》Richard McElreath
  • 《Bayesian Methods for Hackers》Cameron Davidson-Pilon

机器学习应用

  • 《Pattern Recognition and Machine Learning》Christopher Bishop
  • 《Machine Learning: A Probabilistic Perspective》Kevin Murphy
  • 《Probabilistic Machine Learning》Kevin Murphy (2022版)

数学深度

  • 《Probability and Measure》Patrick Billingsley
  • 《Probability: Theory and Examples》Rick Durrett

参考文献

  1. Kolmogorov, A. N. (1933). Grundbegriffe der Wahrscheinlichkeitsrechnung. Springer-Verlag.
  2. Billingsley, P. (1995). Probability and Measure (3rd ed.). Wiley.
  3. Casella, G., & Berger, R. L. (2002). Statistical Inference (2nd ed.). Duxbury Press.
  4. Murphy, K. P. (2022). Probabilistic Machine Learning: An Introduction. MIT Press.
  5. Durrett, R. (2019). Probability: Theory and Examples (5th ed.). Cambridge University Press.
  6. Cover, T. M., & Thomas, J. A. (2006). Elements of Information Theory (2nd ed.). Wiley.
  7. Øksendal, B. (2003). Stochastic Differential Equations: An Introduction (6th ed.). Springer.
  8. MacKay, D. J. C. (2003). Information Theory, Inference, and Learning Algorithms. Cambridge University Press.
  9. Gelman, A., Carlin, J. B., Stern, H. S., Dunson, D. B., Vehtari, A., & Rubin, D. B. (2013). Bayesian Data Analysis (3rd ed.). CRC Press.
  10. Anderson, T. W. (2003). An Introduction to Multivariate Statistical Analysis (3rd ed.). Wiley.
  11. Karatzas, I., & Shreve, S. E. (1991). Brownian Motion and Stochastic Calculus (2nd ed.). Springer.
  12. Jacod, J., & Shiryaev, A. N. (2003). Limit Theorems for Stochastic Processes (2nd ed.). Springer.
  13. Dembo, A., & Zeitouni, O. (2010). Large Deviations Techniques and Applications (2nd ed.). Springer.
  14. Samorodnitsky, G., & Taqqu, M. S. (1994). Stable Non-Gaussian Random Processes. Chapman & Hall.
  15. de Finetti, B. (1974). Theory of Probability (2 vols.). Wiley.
  16. Daley, D. J., & Vere-Jones, D. (2008). An Introduction to the Theory of Point Processes (2nd ed.). Springer.
  17. Resnick, S. I. (2007). Heavy-Tail Phenomena: Probabilistic and Statistical Modeling. Springer.
  18. Cont, R., & Tankov, P. (2004). Financial Modelling with Jump Processes. Chapman & Hall.
  19. Kingman, J. F. C. (1993). Poisson Processes. Oxford University Press.
  20. Goodfellow, I., Bengio, Y., & Courville, A. (2016). Deep Learning. MIT Press.

相关文档