第1章:引言(Introduction)
一、导读
1.1 本章学习目标
第1章是整本《模式识别与机器学习》的开篇之作,它为读者构建了整个领域的宏观图景。Bishop 并没有急于进入数学推导,而是通过一个直觉性的例子——多项式曲线拟合——引出机器学习中最核心的问题:如何在不确定性中做出决策。这种由浅入深的叙事方式是本书最精妙的设计之一。
本章的核心学习目标包括:
- 理解模式识别的基本范式:什么是模式识别?它与机器学习、人工智能之间的关系是什么?
- 掌握概率论的基础角色:为什么概率论是模式识别的数学基础?不确定性为什么不可避免?
- 理解决策论的核心思想:在给定概率模型后,如何做出最优决策?最小化错误率与最小化风险有什么区别?
- 掌握信息论的基本概念:熵、条件熵、互信息、KL散度等概念在模式识别中扮演什么角色?
- 理解模型复杂性与泛化的权衡:过拟合的本质是什么?如何通过正则化来控制模型复杂度?
- 掌握多项式曲线拟合的完整案例:从数据生成到模型训练到评估,完整走一遍机器学习流程。
1.2 为什么第一章如此重要
很多读者会跳过第一章直奔后续的技术细节,这是一个严重的错误。第一章建立了贯穿全书的三个支柱:概率论、决策论和信息论。不理解这三个支柱,就无法真正理解后续章节中每一个算法的设计动机。
Bishop 的核心观点是:模式识别的本质是在不确定性下进行决策。无论是一个简单的分类任务,还是一个复杂的生成模型,我们都在处理不确定性——数据中的噪声、模型参数的不确定性、预测结果的置信度。概率论提供了量化不确定性的语言,决策论提供了在不确定性下做出最优选择的框架,信息论则提供了衡量信息量和模型优劣的标尺。
1.3 核心问题引导
在阅读本章时,请带着以下问题思考:
为什么简单的多项式拟合会出现过拟合?这背后的数学原因是什么?
贝叶斯方法如何处理不确定性?它与频率学派有什么本质区别?
什么是生成模型和判别模型?它们各自的优缺点是什么?
为什么我们需要信息论?熵到底衡量了什么?
正则化为什么能防止过拟合?它的数学本质是什么?
如何选择合适的模型复杂度?有哪些实用的方法?
二、核心概念详解
2.1 多项式曲线拟合:机器学习的缩影
2.1.1 问题定义
假设我们观察到一组数据点 $(x_1, t_1), (x_2, t_2), \ldots, (x_N, t_N)$,其中 $x$ 是输入变量,$t$ 是目标变量。我们希望找到一个函数 $y(x)$,使得对于新的输入 $x$,能够预测对应的 $t$ 值。
最简单的方法是使用多项式函数:
$$y(x, \mathbf{w}) = w_0 + w_1 x + w_2 x^2 + \cdots + w_M x^M = \sum_{j=0}^{M} w_j x^j$$
其中 $M$ 是多项式的阶数,$\mathbf{w} = (w_0, w_1, \ldots, w_M)$ 是多项式的系数。
2.1.2 误差函数
为了找到最优的系数 $\mathbf{w}$,我们需要定义一个衡量标准——误差函数(Error Function),也叫损失函数(Loss Function)。最常用的误差函数是平方误差和:
$$E(\mathbf{w}) = \frac{1}{2} \sum_{n=1}^{N} \{y(x_n, \mathbf{w}) - t_n\}^2$$
前面的系数 $\frac{1}{2}$ 是为了方便后续的数学推导。
2.1.3 最小二乘法
最小二乘法的目标是找到使误差函数最小的 $\mathbf{w}$。由于误差函数是 $\mathbf{w}$ 的二次函数,它关于 $\mathbf{w}$ 的导数是线性的,因此存在唯一的全局最小值。
对 $E(\mathbf{w})$ 关于 $\mathbf{w}$ 求梯度并令其为零:
$$\frac{\partial E}{\partial w_j} = \sum_{n=1}^{N} \left\{\sum_{i=0}^{M} w_i x_n^i - t_n\right\} x_n^j = 0$$
这可以写成矩阵形式:
$$\mathbf{w} = (\mathbf{\Phi}^T \mathbf{\Phi})^{-1} \mathbf{\Phi}^T \mathbf{t}$$
其中 $\mathbf{\Phi}$ 是设计矩阵(Design Matrix),其元素为 $\Phi_{nj} = x_n^j$。
import numpy as np
def polynomial_fit(x, t, M):
"""多项式曲线拟合的最小二乘解"""
N = len(x)
# 构造设计矩阵
Phi = np.zeros((N, M + 1))
for j in range(M + 1):
Phi[:, j] = x ** j
# 最小二乘解
w = np.linalg.inv(Phi.T @ Phi) @ Phi.T @ t
return w
def polynomial_predict(x, w):
"""使用拟合的多项式进行预测"""
M = len(w) - 1
y = np.zeros_like(x)
for j in range(M + 1):
y += w[j] * x ** j
return y
# 生成示例数据
np.random.seed(42)
N = 10
x = np.linspace(0, 1, N)
t = np.sin(2 * np.pi * x) + np.random.normal(0, 0.3, N)
# 不同阶数的多项式拟合
for M in [1, 3, 9]:
w = polynomial_fit(x, t, M)
print(f"M={M}, 权重: {np.round(w, 3)}")2.1.4 过拟合与欠拟合
当我们用不同阶数的多项式拟合同一组数据时,会观察到两种极端现象:
- 欠拟合(Underfitting):多项式阶数太低(如 $M=0$ 或 $M=1$),模型过于简单,无法捕捉数据的趋势。
- 过拟合(Overfitting):多项式阶数太高(如 $M=9$,当 $N=10$ 时),模型完美地通过了所有训练数据点,但在新数据上的预测效果很差。
过拟合的本质是模型"记住"了训练数据中的噪声,而不是学习到数据背后的真实规律。这是机器学习中最核心的挑战之一。
import matplotlib.pyplot as plt
def evaluate_model(x_train, t_train, x_test, t_test, M):
"""评估不同阶数多项式的训练误差和测试误差"""
w = polynomial_fit(x_train, t_train, M)
t_train_pred = polynomial_predict(x_train, w)
t_test_pred = polynomial_predict(x_test, w)
train_error = np.sqrt(np.mean((t_train_pred - t_train) ** 2))
test_error = np.sqrt(np.mean((t_test_pred - t_test) ** 2))
return train_error, test_error
# 生成训练数据和测试数据
np.random.seed(42)
N_train = 10
x_train = np.linspace(0, 1, N_train)
t_train = np.sin(2 * np.pi * x_train) + np.random.normal(0, 0.3, N_train)
N_test = 100
x_test = np.linspace(0, 1, N_test)
t_test = np.sin(2 * np.pi * x_test) + np.random.normal(0, 0.3, N_test)
print(f"{'M':>3} {'训练误差':>10} {'测试误差':>10}")
print("-" * 30)
for M in range(10):
train_err, test_err = evaluate_model(x_train, t_train, x_test, t_test, M)
print(f"{M:3d} {train_err:10.4f} {test_err:10.4f}")运行结果会显示:随着 $M$ 增大,训练误差单调递减(最终趋于零),但测试误差先降后升——在 $M=3$ 或 $M=4$ 附近达到最小值。这就是过拟合的典型表现。
2.2 概率论:不确定性的语言
2.2.1 为什么需要概率论
在模式识别中,不确定性无处不在:
- 测量噪声:传感器采集的数据总是包含噪声
- 有限数据:我们只能观察到有限个样本,无法看到全部数据
- 模型不确定性:即使给定相同的数据,不同的模型也可能给出不同的预测
概率论提供了一套严格的数学框架来量化和处理这些不确定性。
2.2.2 概率的基本规则
两个基本的概率规则:
- 加法规则(Sum Rule):$p(A) = \sum_B p(A, B)$
- 乘法规则(Product Rule):$p(A, B) = p(A|B) p(B)$
由这两个规则可以推导出贝叶斯定理:
$$p(X|Y) = \frac{p(Y|X) p(X)}{p(Y)}$$
其中:
- $p(X|Y)$ 是后验概率(Posterior)
- $p(Y|X)$ 是似然函数(Likelihood)
- $p(X)$ 是先验概率(Prior)
- $p(Y)$ 是证据(Evidence)或边缘似然(Marginal Likelihood)
2.2.3 贝叶斯定理的直觉理解
贝叶斯定理可以理解为一种"信念更新"机制:
$$\text{后验} \propto \text{似然} \times \text{先验}$$
在看到数据之前,我们对参数有一个先验信念 $p(X)$。看到数据后,似然函数 $p(Y|X)$ 衡量了在不同参数值下观察到当前数据的可能性。贝叶斯定理将先验信念与数据证据结合起来,得到更新后的后验信念。
def bayesian_update(prior, likelihood, evidence):
"""贝叶斯更新:后验 = 似然 * 先验 / 证据"""
posterior = likelihood * prior / evidence
return posterior
# 示例:硬币抛掷问题
# 假设我们有一枚硬币,不确定它是否公平
# 先验:认为硬币是公平的(正面概率 theta=0.5 的概率最高)
import numpy as np
from scipy import stats
theta = np.linspace(0, 1, 100)
# 先验:Beta(2, 2),倾向于 theta=0.5
prior = stats.beta.pdf(theta, 2, 2)
# 观察数据:10次抛掷中7次正面
# 似然:Binomial(10, theta) 在 k=7 时的值
likelihood = stats.binom.pmf(7, 10, theta)
# 证据:归一化常数
evidence = np.trapz(likelihood * prior, theta)
# 后验
posterior = bayesian_update(prior, likelihood, evidence)
print(f"后验均值: {np.trapz(theta * posterior, theta):.3f}")
print(f"后验众数: {theta[np.argmax(posterior)]:.3f}")2.2.4 高斯分布
高斯分布(正态分布)是模式识别中最重要的概率分布,原因有三:
中心极限定理:大量独立随机变量的和趋向于高斯分布
数学便利:高斯分布具有许多优美的数学性质
最大熵性质:在给定均值和方差的约束下,高斯分布是熵最大的分布
一元高斯分布的概率密度函数为:
$$\mathcal{N}(x|\mu, \sigma^2) = \frac{1}{\sqrt{2\pi\sigma^2}} \exp\left\{-\frac{(x-\mu)^2}{2\sigma^2}\right\}$$
其中 $\mu$ 是均值,$\sigma^2$ 是方差。
多元高斯分布是高斯分布在高维空间的推广:
$$\mathcal{N}(\mathbf{x}|\boldsymbol{\mu}, \boldsymbol{\Sigma}) = \frac{1}{(2\pi)^{D/2} |\boldsymbol{\Sigma}|^{1/2}} \exp\left\{-\frac{1}{2}(\mathbf{x}-\boldsymbol{\mu})^T \boldsymbol{\Sigma}^{-1} (\mathbf{x}-\boldsymbol{\mu})\right\}$$
其中 $\boldsymbol{\mu}$ 是 $D$ 维均值向量,$\boldsymbol{\Sigma}$ 是 $D \times D$ 的协方差矩阵。
def gaussian_pdf(x, mu, sigma):
"""一元高斯分布概率密度函数"""
return (1 / np.sqrt(2 * np.pi * sigma**2)) * np.exp(-(x - mu)**2 / (2 * sigma**2))
def multivariate_gaussian_pdf(x, mu, Sigma):
"""多元高斯分布概率密度函数"""
D = len(mu)
diff = x - mu
normalization = 1 / ((2 * np.pi)**(D/2) * np.linalg.det(Sigma)**0.5)
exponent = -0.5 * diff.T @ np.linalg.inv(Sigma) @ diff
return normalization * np.exp(exponent)
# 生成高斯分布数据
mu = 0.0
sigma = 1.0
x = np.linspace(-4, 4, 100)
y = gaussian_pdf(x, mu, sigma)
print(f"高斯分布 N(0,1) 在 x=0 处的密度: {gaussian_pdf(0, 0, 1):.4f}")
print(f"高斯分布 N(0,1) 在 x=1 处的密度: {gaussian_pdf(1, 0, 1):.4f}")2.3 决策论:从概率到决策
2.3.1 最小化错误率
在分类问题中,给定输入 $\mathbf{x}$ 和类别 $C_k$,我们希望通过某种决策规则将 $\mathbf{x}$ 分配到某个类别。最简单的决策规则是:选择后验概率最大的类别。
$$\text{决策规则:如果 } p(C_k|\mathbf{x}) > p(C_j|\mathbf{x}) \text{ 对所有 } j \neq k,\text{则分配 } \mathbf{x} \text{ 到 } C_k$$
这个规则等价于最小化分类错误率。
2.3.2 最小化风险
在很多实际问题中,不同类型的错误有不同的代价。例如,在医学诊断中,将癌症患者误诊为健康人的代价远大于将健康人误诊为患者的代价。这时我们需要引入损失函数(Loss Function)$\lambda(\hat{y}, y)$,衡量预测值 $\hat{y}$ 与真实值 $y$ 之间的差异。
最优决策是使期望损失(即风险)最小化的决策:
$$\mathbb{E}[L] = \sum_{k=1}^{K} \sum_{j=1}^{K} \int \lambda_{kj} p(\mathbf{x}, C_k) d\mathbf{x}$$
其中 $\lambda_{kj}$ 是将真实类别为 $C_k$ 的样本误判为 $C_j$ 的代价。
2.3.3 拒绝选项
当模型对某个样本的预测不确定时(即各类别的后验概率接近),我们可以选择"拒绝"该样本,交由人工处理。这是一种实用的策略,特别是在安全关键的应用中。
2.4 信息论:衡量信息的标尺
2.4.1 信息量与熵
信息论的核心概念是信息量。一个事件的信息量与其发生的概率成反比:越不可能的事件发生时,提供的信息量越大。
对于概率为 $p(x)$ 的事件,其信息量定义为:
$$h(x) = -\log_2 p(x)$$
熵(Entropy)是信息量的期望值,衡量了随机变量的不确定性:
$$H[x] = -\sum_x p(x) \log_2 p(x)$$
对于连续变量,对应的概念是微分熵(Differential Entropy):
$$H[\mathbf{x}] = -\int p(\mathbf{x}) \log p(\mathbf{x}) d\mathbf{x}$$
def entropy(p):
"""计算离散分布的熵"""
return -np.sum(p * np.log2(p + 1e-10))
# 示例:比较不同分布的熵
p_uniform = np.array([0.25, 0.25, 0.25, 0.25])
p_biased = np.array([0.7, 0.1, 0.1, 0.1])
p_extreme = np.array([0.97, 0.01, 0.01, 0.01])
print(f"均匀分布的熵: {entropy(p_uniform):.4f} bits")
print(f"有偏分布的熵: {entropy(p_biased):.4f} bits")
print(f"极端分布的熵: {entropy(p_extreme):.4f} bits")输出结果会显示:均匀分布的熵最大(2 bits),因为每个事件等概率时不确定性最高;极端分布的熵最小,因为结果几乎是确定的。
2.4.2 条件熵与互信息
条件熵衡量了在已知另一个随机变量后,剩余的不确定性:
$$H[Y|X] = -\sum_x \sum_y p(x, y) \log p(y|x)$$
互信息(Mutual Information)衡量了两个随机变量之间的相互依赖程度:
$$I[X, Y] = H[X] - H[X|Y] = \sum_x \sum_y p(x, y) \log \frac{p(x, y)}{p(x)p(y)}$$
互信息为零当且仅当 $X$ 和 $Y$ 相互独立。
2.4.3 KL散度
KL散度(Kullback-Leibler Divergence)衡量了两个概率分布之间的"距离":
$$KL(p||q) = \sum_x p(x) \log \frac{p(x)}{q(x)}$$
KL散度不是真正的距离(不满足对称性和三角不等式),但它有一个关键性质:$KL(p||q) \geq 0$,等号成立当且仅当 $p = q$。
def kl_divergence(p, q):
"""计算KL散度 KL(p||q)"""
return np.sum(p * np.log((p + 1e-10) / (q + 1e-10)))
# 示例
p = np.array([0.4, 0.3, 0.2, 0.1])
q1 = np.array([0.25, 0.25, 0.25, 0.25]) # 均匀分布
q2 = np.array([0.35, 0.30, 0.25, 0.10]) # 接近p的分布
print(f"KL(p||q1) = {kl_divergence(p, q1):.4f}")
print(f"KL(p||q2) = {kl_divergence(p, q2):.4f}")2.5 正则化与模型选择
2.5.1 正则化的动机
过拟合的根本原因是模型过于复杂,能够拟合训练数据中的噪声。正则化通过向误差函数中添加一个惩罚项来限制模型的复杂度:
$$\tilde{E}(\mathbf{w}) = E(\mathbf{w}) + \lambda \cdot R(\mathbf{w})$$
其中 $R(\mathbf{w})$ 是正则化项,$\lambda$ 是正则化系数。
最常用的正则化项是 $L_2$ 正则化(岭回归):
$$R(\mathbf{w}) = \frac{1}{2} \|\mathbf{w}\|^2 = \frac{1}{2} \sum_{j=0}^{M} w_j^2$$
加入正则化后的误差函数变为:
$$\tilde{E}(\mathbf{w}) = \frac{1}{2} \sum_{n=1}^{N} \{y(x_n, \mathbf{w}) - t_n\}^2 + \frac{\lambda}{2} \|\mathbf{w}\|^2$$
def polynomial_fit_regularized(x, t, M, lam):
"""带L2正则化的多项式拟合(岭回归)"""
N = len(x)
Phi = np.zeros((N, M + 1))
for j in range(M + 1):
Phi[:, j] = x ** j
# 岭回归的解析解
I = np.eye(M + 1)
I[0, 0] = 0 # 不正则化偏置项
w = np.linalg.inv(Phi.T @ Phi + lam * I) @ Phi.T @ t
return w
# 比较不同正则化系数的效果
M = 9
for lam in [0, 0.001, 0.01, 0.1, 1.0]:
w = polynomial_fit_regularized(x_train, t_train, M, lam)
train_err = np.sqrt(np.mean((polynomial_predict(x_train, w) - t_train) ** 2))
test_err = np.sqrt(np.mean((polynomial_predict(x_test, w) - t_test) ** 2))
print(f"λ={lam:.3f}, 训练误差={train_err:.4f}, 测试误差={test_err:.4f}")2.5.2 偏差-方差分解
偏差-方差分解是理解泛化误差的经典框架。对于回归问题,泛化误差可以分解为:
$$\mathbb{E}[(y - f(\mathbf{x}))^2] = \text{Bias}^2 + \text{Variance} + \text{Noise}$$
- 偏差(Bias):模型预测值与真实值之间的系统性偏差。高偏差意味着模型过于简单(欠拟合)。
- 方差(Variance):模型对训练数据变化的敏感程度。高方差意味着模型过于复杂(过拟合)。
- 噪声(Noise):数据中不可约的随机噪声。
模型复杂度的增加会减小偏差但增大方差,最优的模型复杂度在偏差和方差之间取得平衡。
2.5.3 交叉验证
交叉验证是选择模型超参数(如正则化系数 $\lambda$、多项式阶数 $M$)的实用方法。
K折交叉验证的步骤:
将训练数据分成 $K$ 个大小相近的子集
对于每个子集 $k$:用其余 $K-1$ 个子集训练模型,在第 $k$ 个子集上评估
取 $K$ 次评估结果的平均值作为模型性能的估计
def k_fold_cross_validation(x, t, M, lam, K=5):
"""K折交叉验证"""
N = len(x)
indices = np.arange(N)
np.random.shuffle(indices)
fold_size = N // K
errors = []
for k in range(K):
# 划分训练集和验证集
val_start = k * fold_size
val_end = val_start + fold_size if k < K - 1 else N
val_idx = indices[val_start:val_end]
train_idx = np.concatenate([indices[:val_start], indices[val_end:]])
x_tr, t_tr = x[train_idx], t[train_idx]
x_val, t_val = x[val_idx], t[val_idx]
# 训练并评估
w = polynomial_fit_regularized(x_tr, t_tr, M, lam)
t_pred = polynomial_predict(x_val, w)
error = np.sqrt(np.mean((t_pred - t_val) ** 2))
errors.append(error)
return np.mean(errors)
# 使用交叉验证选择最优正则化系数
lambdas = [0.0001, 0.001, 0.01, 0.1, 1.0]
best_lambda = None
best_error = float('inf')
for lam in lambdas:
cv_error = k_fold_cross_validation(x_train, t_train, M=9, lam=lam, K=5)
print(f"λ={lam:.4f}, CV误差={cv_error:.4f}")
if cv_error < best_error:
best_error = cv_error
best_lambda = lam
print(f"\n最优正则化系数: λ={best_lambda:.4f}")2.6 贝叶斯曲线拟合
2.6.1 参数的贝叶斯方法
在贝叶斯框架中,我们不寻找参数的"最优值",而是计算参数的后验分布。
- 先验:$p(\mathbf{w}) = \mathcal{N}(\mathbf{w}|\mathbf{0}, \alpha^{-1} \mathbf{I})$
- 似然:$p(\mathbf{t}|\mathbf{w}, \beta) = \prod_{n=1}^{N} \mathcal{N}(t_n|y(x_n, \mathbf{w}), \beta^{-1})$
- 后验:$p(\mathbf{w}|\mathbf{t}) \propto p(\mathbf{t}|\mathbf{w}, \beta) p(\mathbf{w})$
对于线性模型和高斯先验,后验分布也是高斯分布:
$$p(\mathbf{w}|\mathbf{t}) = \mathcal{N}(\mathbf{w}|\mathbf{m}_N, \mathbf{S}_N)$$
其中:
- $\mathbf{m}_N = \beta \mathbf{S}_N \mathbf{\Phi}^T \mathbf{t}$
- $\mathbf{S}_N^{-1} = \alpha \mathbf{I} + \beta \mathbf{\Phi}^T \mathbf{\Phi}$
2.6.2 预测分布
在贝叶斯框架中,预测时需要考虑参数的所有可能值,按后验概率加权:
$$p(t|\mathbf{x}, \mathbf{t}) = \int p(t|\mathbf{x}, \mathbf{w}) p(\mathbf{w}|\mathbf{t}) d\mathbf{w}$$
对于线性回归模型,预测分布也是高斯分布:
$$p(t|\mathbf{x}, \mathbf{t}) = \mathcal{N}(t|\mathbf{m}_N^T \boldsymbol{\phi}(\mathbf{x}), \sigma_N^2(\mathbf{x}))$$
其中预测方差为:
$$\sigma_N^2(\mathbf{x}) = \frac{1}{\beta} + \boldsymbol{\phi}(\mathbf{x})^T \mathbf{S}_N \boldsymbol{\phi}(\mathbf{x})$$
第一项 $\frac{1}{\beta}$ 是数据噪声,第二项 $\boldsymbol{\phi}(\mathbf{x})^T \mathbf{S}_N \boldsymbol{\phi}(\mathbf{x})$ 是模型不确定性。
def bayesian_linear_regression(x_train, t_train, x_test, alpha, beta):
"""贝叶斯线性回归"""
N = len(x_train)
M = 9 # 多项式阶数
# 构造设计矩阵
Phi_train = np.column_stack([x_train ** j for j in range(M + 1)])
Phi_test = np.column_stack([x_test ** j for j in range(M + 1)])
# 后验参数
S_N_inv = alpha * np.eye(M + 1) + beta * Phi_train.T @ Phi_train
S_N = np.linalg.inv(S_N_inv)
m_N = beta * S_N @ Phi_train.T @ t_train
# 预测分布
pred_mean = Phi_test @ m_N
pred_var = np.array([1/beta + Phi_test[i] @ S_N @ Phi_test[i] for i in range(len(x_test))])
return pred_mean, pred_var
# 示例
x_test_fine = np.linspace(0, 1, 200)
pred_mean, pred_var = bayesian_linear_regression(x_train, t_train, x_test_fine, alpha=2.0, beta=25.0)
pred_std = np.sqrt(pred_var)
print(f"预测均值范围: [{pred_mean.min():.3f}, {pred_mean.max():.3f}]")
print(f"预测标准差范围: [{pred_std.min():.3f}, {pred_std.max():.3f}]")三、实战案例
3.1 完整的曲线拟合实验
import numpy as np
import matplotlib.pyplot as plt
def run_curve_fitting_experiment():
"""完整的曲线拟合实验:展示过拟合、正则化和贝叶斯方法"""
# 1. 数据生成
np.random.seed(42)
N = 10
x = np.linspace(0, 1, N)
true_function = np.sin(2 * np.pi * x)
noise = np.random.normal(0, 0.3, N)
t = true_function + noise
# 2. 不同阶数的多项式拟合
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
x_fine = np.linspace(0, 1, 100)
for idx, M in enumerate([0, 1, 3, 9]):
ax = axes[idx // 2, idx % 2]
w = polynomial_fit(x, t, M)
y_fine = polynomial_predict(x_fine, w)
ax.plot(x_fine, np.sin(2 * np.pi * x_fine), 'g--', label='True function', linewidth=2)
ax.plot(x_fine, y_fine, 'b-', label=f'M={M} polynomial', linewidth=2)
ax.scatter(x, t, c='red', s=50, zorder=5, label='Data points')
ax.set_title(f'M={M}')
ax.set_ylim(-1.5, 1.5)
ax.legend(fontsize=8)
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('curve_fitting.png', dpi=150)
plt.close()
# 3. 偏差-方差分析
n_trials = 100
M_values = range(10)
bias_squared = []
variance = []
for M in M_values:
predictions = []
for trial in range(n_trials):
x_trial = np.linspace(0, 1, N)
t_trial = np.sin(2 * np.pi * x_trial) + np.random.normal(0, 0.3, N)
w = polynomial_fit(x_trial, t_trial, M)
predictions.append(polynomial_predict(x_fine, w))
predictions = np.array(predictions)
mean_prediction = predictions.mean(axis=0)
true_values = np.sin(2 * np.pi * x_fine)
bias_sq = np.mean((mean_prediction - true_values) ** 2)
var = np.mean(np.var(predictions, axis=0))
bias_squared.append(bias_sq)
variance.append(var)
print("偏差-方差分析:")
print(f"{'M':>3} {'Bias²':>10} {'Variance':>10} {'Total':>10}")
for M, b, v in zip(M_values, bias_squared, variance):
print(f"{M:3d} {b:10.4f} {v:10.4f} {b+v:10.4f}")
return bias_squared, variance
bias_sq, var = run_curve_fitting_experiment()3.2 贝叶斯模型比较
def bayesian_model_comparison(x, t):
"""使用贝叶斯因子比较不同阶数的多项式模型"""
M_values = range(6)
log_evidences = []
for M in M_values:
N = len(x)
alpha = 0.005
beta = 25.0
Phi = np.column_stack([x ** j for j in range(M + 1)])
# 后验协方差
S_N_inv = alpha * np.eye(M + 1) + beta * Phi.T @ Phi
S_N = np.linalg.inv(S_N_inv)
m_N = beta * S_N @ Phi.T @ t
# 对数边缘似然(证据)
# ln p(t|alpha,beta) = (M+1)/2 * ln(alpha) + N/2 * ln(beta) - E(m_N)
# - 1/2 * ln|S_N_inv| - N/2 * ln(2*pi)
E_mN = beta / 2 * np.sum((t - Phi @ m_N) ** 2) + alpha / 2 * m_N @ m_N
log_evidence = (M + 1) / 2 * np.log(alpha) + N / 2 * np.log(beta) \
- E_mN - 0.5 * np.log(np.linalg.det(S_N_inv)) \
- N / 2 * np.log(2 * np.pi)
log_evidences.append(log_evidence)
print(f"M={M}, ln(evidence)={log_evidence:.2f}")
# 找到最优模型
best_M = M_values[np.argmax(log_evidences)]
print(f"\n贝叶斯模型选择结果: 最优 M = {best_M}")
return log_evidences
# 运行模型比较
np.random.seed(42)
x = np.linspace(0, 1, 10)
t = np.sin(2 * np.pi * x) + np.random.normal(0, 0.3, 10)
log_evidences = bayesian_model_comparison(x, t)3.3 信息论在特征选择中的应用
def mutual_information_feature_selection(X, y, feature_names):
"""使用互信息进行特征选择"""
n_features = X.shape[1]
mi_scores = []
for i in range(n_features):
# 离散化连续特征
x_binned = np.digitize(X[:, i], bins=np.linspace(X[:, i].min(), X[:, i].max(), 20))
# 计算互信息
# I(X;Y) = H(X) + H(Y) - H(X,Y)
px = np.bincount(x_binned) / len(x_binned)
py = np.bincount(y) / len(y)
pxy = np.zeros((len(np.unique(x_binned)), len(np.unique(y))))
for xi, yi in zip(x_binned, y):
pxy[xi, yi] += 1
pxy /= pxy.sum()
hx = entropy(px)
hy = entropy(py)
hxy = entropy(pxy.flatten()[pxy.flatten() > 0])
mi = hx + hy - hxy
mi_scores.append(mi)
print(f"特征 '{feature_names[i]}': MI = {mi:.4f} bits")
# 按互信息排序
sorted_indices = np.argsort(mi_scores)[::-1]
print("\n特征重要性排序:")
for rank, idx in enumerate(sorted_indices):
print(f" {rank+1}. {feature_names[idx]} (MI={mi_scores[idx]:.4f})")
return mi_scores
# 示例:使用鸢尾花数据集
from sklearn.datasets import load_iris
iris = load_iris()
X = iris.data
y = iris.target
feature_names = iris.feature_names
mi_scores = mutual_information_feature_selection(X, y, feature_names)四、本章小结
第1章为整本《模式识别与机器学习》奠定了理论基础,建立了三个核心支柱:
概率论:提供了量化不确定性的数学语言。贝叶斯定理是连接先验知识和数据证据的桥梁,高斯分布因其优美的数学性质和中心极限定理而成为最重要的概率分布。
决策论:提供了在不确定性下做出最优决策的框架。最小化错误率是最简单的决策准则,但在实际应用中,我们需要考虑不同错误的不同代价,使用最小化风险的决策准则。
信息论:提供了衡量信息量和模型优劣的标尺。熵衡量不确定性,互信息衡量变量间的依赖关系,KL散度衡量分布间的差异。
多项式曲线拟合的案例揭示了机器学习最核心的挑战:模型复杂度与泛化能力的权衡。过拟合的本质是模型记住了噪声而非规律,正则化和贝叶斯方法是应对过拟合的两大武器。偏差-方差分解为理解泛化误差提供了理论框架,交叉验证则是实践中选择模型复杂度的标准方法。
这些概念将在后续章节中不断深化和扩展。第2章将深入研究各种概率分布,第3-4章将探讨线性模型,第5章引入神经网络,第6-7章讨论核方法,第8-9章讲解图模型和混合模型,第10章介绍近似推断方法。
五、思考与练习
思考题
为什么贝叶斯方法天然具有防止过拟合的能力?请从先验分布的角度解释。
如果训练数据中存在大量异常值(outliers),使用平方误差函数会有什么问题?你会选择什么替代方案?
互信息 $I[X,Y]$ 和 KL散度 $KL(p(x,y) || p(x)p(y))$ 之间有什么关系?
为什么高斯分布在机器学习中如此重要?除了中心极限定理,还有哪些原因?
当训练数据量趋向无穷大时,贝叶斯后验分布会发生什么变化?
编程练习
正则化路径:实现多项式回归的正则化路径(Regularization Path),绘制权重 $w_j$ 随正则化系数 $\lambda$ 变化的曲线,观察正则化对模型参数的影响。
交叉验证实验:使用真实数据集(如波士顿房价数据集),比较 $K$ 折交叉验证和留一法交叉验证的结果差异,分析 $K$ 值对模型选择的影响。
贝叶斯预测区间:实现贝叶斯曲线拟合,绘制预测均值和 95% 预测区间。观察在训练数据稀疏的区域,预测区间是否变宽。