6模式识别与机器学习

核方法

非线性映射

核函数对偶表示高斯过程

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第6章:核方法(Kernel Methods)

一、导读

6.1 本章学习目标

第6章介绍了核方法——一种优雅而强大的机器学习技术。核方法的核心思想是核技巧(Kernel Trick):通过隐式地将数据映射到高维特征空间,在高维空间中执行线性算法,从而在原始空间中获得非线性决策边界。整个过程不需要显式计算高维特征,只需要计算原始空间中的核函数值。

本章的核心学习目标包括:

  • 理解核技巧的本质:为什么不需要显式计算高维特征?核函数与特征映射有什么关系?
  • 掌握对偶表示:线性模型的参数可以用训练数据的线性组合表示,这意味着什么?
  • 深入理解支持向量机:SVM的优化问题如何推导?支持向量的几何含义是什么?
  • 掌握常见核函数:多项式核、高斯核(RBF核)、sigmoid核各自的特点和适用场景。
  • 理解高斯过程:高斯过程回归和分类的基本原理是什么?它与贝叶斯线性回归有什么关系?
  • 了解核方法的计算挑战:核方法的测试阶段为什么需要所有训练数据?如何解决?

6.2 为什么本章如此重要

核方法是机器学习中最优美的理论成果之一。它连接了多个看似不相关的领域:线性代数(特征映射)、优化理论(对偶问题)、概率论(高斯过程)、函数分析(再生核希尔伯特空间)。

核方法在实际应用中也非常成功。支持向量机(SVM)在深度学习兴起之前是最强大的分类算法之一,至今仍在许多任务上表现出色。高斯过程提供了灵活的贝叶斯非参数模型,在贝叶斯优化、时空建模等领域有广泛应用。

更重要的是,核方法的理论思想——对偶表示、核技巧——深刻影响了深度学习的发展。注意力机制可以理解为一种可学习的核函数,神经切线核(NTK)理论揭示了宽神经网络与核方法的深层联系。

6.3 核心问题引导

在阅读本章时,请带着以下问题思考:

核函数为什么能够隐式地在高维空间中工作?Mercer定理说了什么?

支持向量机的"支持向量"为什么重要?它们如何决定决策边界?

软间隔SVM中的参数C如何控制模型的复杂度?它与正则化系数有什么关系?

高斯过程回归和核岭回归(Kernel Ridge Regression)有什么关系?

核方法的计算复杂度是多少?当训练数据量很大时会遇到什么问题?

如何选择核函数和核参数?有哪些实用的策略?


二、核心概念详解

6.1 对偶表示

6.1.1 线性模型的对偶形式

在第3章中,线性回归的解为:

$$\mathbf{w} = (\mathbf{\Phi}^T \mathbf{\Phi})^{-1} \mathbf{\Phi}^T \mathbf{t}$$

利用矩阵求逆引理(Woodbury公式),可以将解表示为训练数据的线性组合:

$$\mathbf{w} = \mathbf{\Phi}^T \mathbf{a}$$

其中 $\mathbf{a} = (\mathbf{\Phi} \mathbf{\Phi}^T + \lambda \mathbf{I})^{-1} \mathbf{t} = (\mathbf{K} + \lambda \mathbf{I})^{-1} \mathbf{t}$

这里 $\mathbf{K} = \mathbf{\Phi} \mathbf{\Phi}^T$ 是Gram矩阵,其元素为 $K_{nm} = \boldsymbol{\phi}(\mathbf{x}_n)^T \boldsymbol{\phi}(\mathbf{x}_m)$。

对偶表示的关键洞察:预测只依赖于特征向量的内积,而不需要显式计算特征向量。

$$y(\mathbf{x}) = \mathbf{w}^T \boldsymbol{\phi}(\mathbf{x}) = \sum_{n=1}^{N} a_n \boldsymbol{\phi}(\mathbf{x}_n)^T \boldsymbol{\phi}(\mathbf{x}) = \sum_{n=1}^{N} a_n k(\mathbf{x}_n, \mathbf{x})$$

6.1.2 核技巧

核技巧的核心思想:如果算法只依赖于数据的内积 $\boldsymbol{\phi}(\mathbf{x}_n)^T \boldsymbol{\phi}(\mathbf{x}_m)$,那么我们可以用核函数 $k(\mathbf{x}_n, \mathbf{x}_m)$ 替代内积,而无需知道特征映射 $\boldsymbol{\phi}$ 的具体形式。

定义:核函数 $k(\mathbf{x}, \mathbf{x}') = \boldsymbol{\phi}(\mathbf{x})^T \boldsymbol{\phi}(\mathbf{x}')$

这等价于在高维特征空间 $\boldsymbol{\phi}$ 中计算内积,但只需要在原始空间中计算核函数。

python
import numpy as np
import matplotlib.pyplot as plt

def polynomial_kernel(x1, x2, degree=3, coef0=1):
    """多项式核函数"""
    return (x1 @ x2 + coef0) ** degree

def rbf_kernel(x1, x2, gamma=1.0):
    """高斯径向基核函数"""
    sq_dists = np.sum(x1**2, axis=1, keepdims=True) + np.sum(x2**2, axis=1) - 2 * x1 @ x2.T
    return np.exp(-gamma * sq_dists)

def linear_kernel(x1, x2):
    """线性核函数"""
    return x1 @ x2.T

# 示例:展示核函数如何隐式映射到高维
x = np.array([[1, 0], [0, 1], [1, 1]])

# 多项式核 K(x,x') = (x^T x' + 1)^2 等价于特征映射
# phi(x) = [x1^2, sqrt(2)*x1*x2, x2^2, sqrt(2)*x1, sqrt(2)*x2, 1]
K_poly = polynomial_kernel(x, x, degree=2, coef0=1)
print("多项式核矩阵 (degree=2):")
print(np.round(K_poly, 2))

# RBF核
K_rbf = rbf_kernel(x, x, gamma=1.0)
print("\nRBF核矩阵 (gamma=1.0):")
print(np.round(K_rbf, 2))

6.2 常见核函数

6.2.1 核函数列表

核函数表达式特点
线性核$k(\mathbf{x},\mathbf{x}') = \mathbf{x}^T\mathbf{x}'$等价于原始空间线性模型
多项式核$k(\mathbf{x},\mathbf{x}') = (\mathbf{x}^T\mathbf{x}' + c)^d$有限维特征空间
高斯RBF核$k(\mathbf{x},\mathbf{x}') = \exp(-\gamma\\mathbf{x}-\mathbf{x}'\^2)$无穷维特征空间
Sigmoid核$k(\mathbf{x},\mathbf{x}') = \tanh(\alpha\mathbf{x}^T\mathbf{x}' + c)$类似两层神经网络
Laplacian核$k(\mathbf{x},\mathbf{x}') = \exp(-\gamma\\mathbf{x}-\mathbf{x}'\)$对异常值更鲁棒

6.2.2 Mercer定理

Mercer定理给出了一个函数成为有效核函数的充要条件:

一个对称函数 $k(\mathbf{x}, \mathbf{x}')$ 是有效核函数,当且仅当对于任意有限集 $\{\mathbf{x}_1, \ldots, \mathbf{x}_N\}$,对应的Gram矩阵 $\mathbf{K}$ 是半正定的。

这个定理的重要性在于:我们不需要知道特征映射 $\boldsymbol{\phi}$ 的具体形式,只需要验证Gram矩阵的半正定性。

python
def verify_positive_definite():
    """验证核矩阵的正定性"""
    np.random.seed(42)
    X = np.random.randn(20, 2)
    
    kernels = {
        'Linear': lambda x1, x2: linear_kernel(x1, x2),
        'Polynomial (d=2)': lambda x1, x2: polynomial_kernel(x1, x2, degree=2),
        'RBF (γ=1)': lambda x1, x2: rbf_kernel(x1, x2, gamma=1.0),
        'RBF (γ=0.1)': lambda x1, x2: rbf_kernel(x1, x2, gamma=0.1),
    }
    
    for name, kernel_func in kernels.items():
        K = kernel_func(X, X)
        eigenvalues = np.linalg.eigvalsh(K)
        is_pd = np.all(eigenvalues >= -1e-10)
        print(f"{name}: 最小特征值={eigenvalues.min():.6f}, 正定={is_pd}")

verify_positive_definite()

6.3 支持向量机

6.3.1 最大间隔分类器

支持向量机的核心思想:找到最大间隔的决策超平面。

间隔(Margin):决策超平面到最近训练样本的距离。最大化间隔等价于最小化 $\|\mathbf{w}\|^2$。

优化问题(硬间隔SVM):

$$\min_{\mathbf{w}, b} \frac{1}{2} \|\mathbf{w}\|^2 \quad \text{s.t.} \quad t_n(\mathbf{w}^T \boldsymbol{\phi}(\mathbf{x}_n) + b) \geq 1, \forall n$$

6.3.2 软间隔SVM

对于线性不可分的数据,引入松弛变量 $\xi_n \geq 0$:

$$\min_{\mathbf{w}, b, \boldsymbol{\xi}} \frac{1}{2} \|\mathbf{w}\|^2 + C \sum_{n=1}^{N} \xi_n$$

$$\text{s.t.} \quad t_n(\mathbf{w}^T \boldsymbol{\phi}(\mathbf{x}_n) + b) \geq 1 - \xi_n, \quad \xi_n \geq 0$$

参数 $C$ 控制间隔大小和分类错误的权衡:

  • $C$ 大:强调正确分类,间隔小(可能过拟合)
  • $C$ 小:允许更多分类错误,间隔大(可能欠拟合)

6.3.3 对偶问题

SVM的对偶问题:

$$\max_{\mathbf{a}} \sum_{n=1}^{N} a_n - \frac{1}{2} \sum_{n=1}^{N} \sum_{m=1}^{N} a_n a_m t_n t_m k(\mathbf{x}_n, \mathbf{x}_m)$$

$$\text{s.t.} \quad 0 \leq a_n \leq C, \quad \sum_{n=1}^{N} a_n t_n = 0$$

对偶问题的关键性质:

  • 只依赖于核函数 $k(\mathbf{x}_n, \mathbf{x}_m)$
  • 大部分 $a_n = 0$,对应的训练点不影响决策边界
  • $a_n > 0$ 的点称为支持向量,它们决定了决策边界
python
class SimpleSVM:
    """简化版SVM(SMO算法的简化实现)"""
    
    def __init__(self, C=1.0, kernel='rbf', gamma=1.0, max_iter=100):
        self.C = C
        self.kernel = kernel
        self.gamma = gamma
        self.max_iter = max_iter
    
    def _compute_kernel(self, X1, X2):
        if self.kernel == 'rbf':
            return rbf_kernel(X1, X2, self.gamma)
        elif self.kernel == 'linear':
            return linear_kernel(X1, X2)
        elif self.kernel == 'polynomial':
            return polynomial_kernel(X1, X2)
    
    def fit(self, X, y):
        N = len(X)
        self.X_train = X
        self.y_train = y
        t = 2 * y - 1  # 转换为 {-1, 1}
        
        K = self._compute_kernel(X, X)
        
        # 简化版SMO
        alpha = np.zeros(N)
        b = 0
        
        for iteration in range(self.max_iter):
            for i in range(N):
                # 计算预测
                f = np.sum(alpha * t * K[i]) + b
                E_i = f - t[i]
                
                # KKT条件检查
                if (t[i] * E_i < -0.001 and alpha[i] < self.C) or \
                   (t[i] * E_i > 0.001 and alpha[i] > 0):
                    # 选择第二个样本
                    j = np.random.randint(N)
                    while j == i:
                        j = np.random.randint(N)
                    
                    f_j = np.sum(alpha * t * K[j]) + b
                    E_j = f_j - t[j]
                    
                    alpha_i_old = alpha[i]
                    alpha_j_old = alpha[j]
                    
                    # 计算上下界
                    if t[i] != t[j]:
                        L = max(0, alpha[j] - alpha[i])
                        H = min(self.C, self.C + alpha[j] - alpha[i])
                    else:
                        L = max(0, alpha[i] + alpha[j] - self.C)
                        H = min(self.C, alpha[i] + alpha[j])
                    
                    if L >= H:
                        continue
                    
                    eta = 2 * K[i, j] - K[i, i] - K[j, j]
                    if eta >= 0:
                        continue
                    
                    alpha[j] -= t[j] * (E_i - E_j) / eta
                    alpha[j] = np.clip(alpha[j], L, H)
                    
                    alpha[i] += t[i] * t[j] * (alpha_j_old - alpha[j])
                    
                    # 更新b
                    b1 = b - E_i - t[i] * (alpha[i] - alpha_i_old) * K[i, i] \
                         - t[j] * (alpha[j] - alpha_j_old) * K[i, j]
                    b2 = b - E_j - t[i] * (alpha[i] - alpha_i_old) * K[i, j] \
                         - t[j] * (alpha[j] - alpha_j_old) * K[j, j]
                    
                    if 0 < alpha[i] < self.C:
                        b = b1
                    elif 0 < alpha[j] < self.C:
                        b = b2
                    else:
                        b = (b1 + b2) / 2
        
        self.alpha = alpha
        self.b = b
        self.sv_indices = np.where(alpha > 1e-5)[0]
        
        return self
    
    def predict(self, X):
        K = self._compute_kernel(X, self.X_train)
        f = K @ (self.alpha * (2 * self.y_train - 1)) + self.b
        return (f > 0).astype(int)

# 示例
np.random.seed(42)
N = 100
X_svm = np.vstack([
    np.random.randn(N//2, 2) + [2, 2],
    np.random.randn(N//2, 2) + [-2, -2]
])
y_svm = np.array([0]*(N//2) + [1]*(N//2))

svm = SimpleSVM(C=1.0, kernel='rbf', gamma=0.5)
svm.fit(X_svm, y_svm)

predictions = svm.predict(X_svm)
accuracy = np.mean(predictions == y_svm)
print(f"SVM训练准确率: {accuracy:.4f}")
print(f"支持向量数量: {len(svm.sv_indices)} / {N}")

6.4 高斯过程

6.4.1 高斯过程的定义

高斯过程(Gaussian Process, GP)是无限维的高斯分布。一个高斯过程完全由均值函数 $m(\mathbf{x})$ 和协方差函数(核函数)$k(\mathbf{x}, \mathbf{x}')$ 确定:

$$f(\mathbf{x}) \sim \mathcal{GP}(m(\mathbf{x}), k(\mathbf{x}, \mathbf{x}'))$$

对于任意有限集 $\{\mathbf{x}_1, \ldots, \mathbf{x}_N\}$,函数值 $\mathbf{f} = (f(\mathbf{x}_1), \ldots, f(\mathbf{x}_N))^T$ 服从联合高斯分布:

$$\mathbf{f} \sim \mathcal{N}(\mathbf{m}, \mathbf{K})$$

其中 $m_i = m(\mathbf{x}_i)$,$K_{ij} = k(\mathbf{x}_i, \mathbf{x}_j)$。

6.4.2 高斯过程回归

给定训练数据 $\{(\mathbf{x}_n, t_n)\}_{n=1}^N$ 和测试点 $\mathbf{x}_*$,预测分布为:

$$p(t_|\mathbf{x}_, \mathbf{X}, \mathbf{t}) = \mathcal{N}(t_|\mu_, \sigma_*^2)$$

其中:

  • $\mu_ = \mathbf{k}_^T (\mathbf{K} + \sigma^2 \mathbf{I})^{-1} \mathbf{t}$
  • $\sigma_^2 = k(\mathbf{x}_, \mathbf{x}_) - \mathbf{k}_^T (\mathbf{K} + \sigma^2 \mathbf{I})^{-1} \mathbf{k}_*$

这里 $\mathbf{k}_ = (k(\mathbf{x}_, \mathbf{x}_1), \ldots, k(\mathbf{x}_*, \mathbf{x}_N))^T$。

python
def gaussian_process_regression(X_train, t_train, X_test, kernel_func, sigma2=0.1):
    """高斯过程回归"""
    K = kernel_func(X_train, X_train) + sigma2 * np.eye(len(X_train))
    K_inv = np.linalg.inv(K)
    
    # 测试点与训练点的核
    K_star = kernel_func(X_test, X_train)
    K_ss = kernel_func(X_test, X_test)
    
    # 预测分布
    mu_star = K_star @ K_inv @ t_train
    var_star = np.diag(K_ss - K_star @ K_inv @ K_star.T)
    var_star = np.maximum(var_star, 0)  # 数值稳定性
    
    return mu_star, var_star

# 示例
np.random.seed(42)
N_train = 15
X_gp = np.sort(np.random.uniform(-3, 3, N_train))
t_gp = np.sin(X_gp) + 0.2 * np.random.randn(N_train)

X_test_gp = np.linspace(-4, 4, 200)

mu_gp, var_gp = gaussian_process_regression(
    X_gp.reshape(-1, 1), t_gp, X_test_gp.reshape(-1, 1),
    kernel_func=lambda x1, x2: rbf_kernel(x1, x2, gamma=1.0),
    sigma2=0.04
)
std_gp = np.sqrt(var_gp)

# 可视化
fig, ax = plt.subplots(figsize=(10, 6))
ax.scatter(X_gp, t_gp, c='red', s=50, zorder=5, label='Training data')
ax.plot(X_test_gp, mu_gp, 'b-', linewidth=2, label='GP prediction')
ax.fill_between(X_test_gp, mu_gp - 2*std_gp, mu_gp + 2*std_gp, 
                alpha=0.2, color='blue', label='95% CI')
ax.plot(X_test_gp, np.sin(X_test_gp), 'g--', linewidth=2, label='True function')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('Gaussian Process Regression')
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('gaussian_process.png', dpi=150)
plt.close()

print(f"预测均值范围: [{mu_gp.min():.3f}, {mu_gp.max():.3f}]")
print(f"预测标准差范围: [{std_gp.min():.3f}, {std_gp.max():.3f}]")

6.4.3 高斯过程与贝叶斯线性回归的关系

高斯过程回归等价于无穷维的贝叶斯线性回归。当基函数的数量趋向无穷时,贝叶斯线性回归的预测分布收敛到高斯过程的预测分布。核函数 $k(\mathbf{x}, \mathbf{x}')$ 对应于基函数的内积 $\boldsymbol{\phi}(\mathbf{x})^T \boldsymbol{\phi}(\mathbf{x}')$。

6.5 核方法的计算挑战

6.5.1 复杂度分析

  • 训练阶段:需要计算 $N \times N$ 的Gram矩阵,并求逆,复杂度 $O(N^3)$
  • 测试阶段:需要计算测试点与所有训练点的核函数值,复杂度 $O(N)$

当 $N$ 很大时(如 $N > 10000$),训练阶段的 $O(N^3)$ 复杂度变得不可接受。

6.5.2 加速方法

  • 稀疏核机(第7章):选择少量代表性数据点
  • Nyström方法:随机采样列来近似Gram矩阵
  • 随机特征:用随机傅里叶特征近似RBF核
  • inducing points:选择一组诱导点来近似后验
python
def random_fourier_features(X, gamma, D=100):
    """随机傅里叶特征近似RBF核"""
    d = X.shape[1]
    np.random.seed(42)
    W = np.random.randn(d, D) * np.sqrt(2 * gamma)
    b = np.random.uniform(0, 2*np.pi, D)
    
    Z = np.sqrt(2.0 / D) * np.cos(X @ W + b)
    return Z

# 验证:随机特征近似的核矩阵应该接近原始RBF核矩阵
np.random.seed(42)
X_rf = np.random.randn(50, 2)
gamma = 1.0

K_exact = rbf_kernel(X_rf, X_rf, gamma)
Z = random_fourier_features(X_rf, gamma, D=500)
K_approx = Z @ Z.T

error = np.mean((K_exact - K_approx) ** 2)
print(f"随机特征近似误差 (D=500): {error:.6f}")

三、实战案例

6.1 SVM分类实验

python
def svm_classification_experiment():
    """SVM分类实验:比较不同核函数和参数"""
    from sklearn.svm import SVC
    from sklearn.datasets import make_moons
    from sklearn.model_selection import cross_val_score
    
    # 生成月牙形数据
    X_moons, y_moons = make_moons(n_samples=300, noise=0.15, random_state=42)
    
    fig, axes = plt.subplots(1, 3, figsize=(15, 5))
    
    configs = [
        ('Linear', 'linear', {}),
        ('RBF (γ=0.1)', 'rbf', {'gamma': 0.1}),
        ('RBF (γ=10)', 'rbf', {'gamma': 10}),
    ]
    
    for ax, (title, kernel, params) in zip(axes, configs):
        svm = SVC(C=1.0, kernel=kernel, **params)
        svm.fit(X_moons, y_moons)
        
        # 决策边界
        h = 0.02
        x_min, x_max = X_moons[:, 0].min() - 0.5, X_moons[:, 0].max() + 0.5
        y_min, y_max = X_moons[:, 1].min() - 0.5, X_moons[:, 1].max() + 0.5
        xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
        Z = svm.predict(np.c_[xx.ravel(), yy.ravel()])
        Z = Z.reshape(xx.shape)
        
        ax.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.RdBu)
        ax.scatter(X_moons[:, 0], X_moons[:, 1], c=y_moons, cmap=plt.cm.RdBu, 
                    edgecolors='k', s=20)
        ax.set_title(title)
        ax.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.savefig('svm_kernels.png', dpi=150)
    plt.close()
    
    # 交叉验证
    for title, kernel, params in configs:
        svm = SVC(C=1.0, kernel=kernel, **params)
        scores = cross_val_score(svm, X_moons, y_moons, cv=5)
        print(f"{title}: 准确率={scores.mean():.4f} ± {scores.std():.4f}")

svm_classification_experiment()

6.2 核岭回归

python
def kernel_ridge_regression():
    """核岭回归:使用核方法的正则化线性回归"""
    np.random.seed(42)
    
    # 生成非线性回归数据
    N = 50
    X_krr = np.sort(np.random.uniform(-3, 3, N))
    t_krr = np.sin(X_krr) + 0.2 * np.random.randn(N)
    
    X_train_krr = X_krr.reshape(-1, 1)
    
    # 核岭回归
    lam = 0.1
    K = rbf_kernel(X_train_krr, X_train_krr, gamma=1.0)
    alpha = np.linalg.solve(K + lam * np.eye(N), t_krr)
    
    # 预测
    X_test_krr = np.linspace(-4, 4, 200).reshape(-1, 1)
    K_test = rbf_kernel(X_test_krr, X_train_krr, gamma=1.0)
    y_pred = K_test @ alpha
    
    fig, ax = plt.subplots(figsize=(10, 6))
    ax.scatter(X_krr, t_krr, c='red', s=50, zorder=5, label='Training data')
    ax.plot(X_test_krr, y_pred, 'b-', linewidth=2, label='Kernel Ridge Regression')
    ax.plot(X_test_krr, np.sin(X_test_krr), 'g--', linewidth=2, label='True function')
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_title('Kernel Ridge Regression (RBF kernel)')
    ax.legend()
    ax.grid(True, alpha=0.3)
    plt.tight_layout()
    plt.savefig('kernel_ridge_regression.png', dpi=150)
    plt.close()
    
    mse = np.mean((y_pred - np.sin(X_test_krr)) ** 2)
    print(f"测试MSE: {mse:.6f}")

kernel_ridge_regression()

6.3 核参数选择

python
def kernel_parameter_selection():
    """使用交叉验证选择核参数"""
    from sklearn.svm import SVC
    from sklearn.model_selection import GridSearchCV
    from sklearn.datasets import load_breast_cancer
    from sklearn.preprocessing import StandardScaler
    
    # 加载数据
    data = load_breast_cancer()
    X_bc = data.data
    y_bc = data.target
    
    # 标准化
    scaler = StandardScaler()
    X_bc = scaler.fit_transform(X_bc)
    
    # 网格搜索
    param_grid = {
        'C': [0.1, 1, 10, 100],
        'gamma': [0.001, 0.01, 0.1, 1],
        'kernel': ['rbf']
    }
    
    grid_search = GridSearchCV(SVC(), param_grid, cv=5, scoring='accuracy', n_jobs=-1)
    grid_search.fit(X_bc, y_bc)
    
    print(f"最优参数: {grid_search.best_params_}")
    print(f"最优交叉验证准确率: {grid_search.best_score_:.4f}")
    
    # 热力图
    results = grid_search.cv_results_
    C_values = param_grid['C']
    gamma_values = param_grid['gamma']
    
    scores = np.array(results['mean_test_score']).reshape(len(C_values), len(gamma_values))
    
    fig, ax = plt.subplots(figsize=(8, 6))
    im = ax.imshow(scores, cmap='viridis', aspect='auto')
    ax.set_xticks(range(len(gamma_values)))
    ax.set_xticklabels(gamma_values)
    ax.set_yticks(range(len(C_values)))
    ax.set_yticklabels(C_values)
    ax.set_xlabel('gamma')
    ax.set_ylabel('C')
    ax.set_title('SVM Cross-Validation Accuracy')
    plt.colorbar(im)
    
    for i in range(len(C_values)):
        for j in range(len(gamma_values)):
            ax.text(j, i, f'{scores[i,j]:.3f}', ha='center', va='center', 
                    color='white' if scores[i,j] < 0.95 else 'black', fontsize=10)
    
    plt.tight_layout()
    plt.savefig('svm_parameter_selection.png', dpi=150)
    plt.close()

kernel_parameter_selection()

四、本章小结

第6章系统介绍了核方法的理论和应用:

对偶表示:线性模型的参数可以表示为训练数据的线性组合,预测只依赖于特征向量的内积。

核技巧:通过核函数隐式地在高维(甚至无穷维)特征空间中工作,无需显式计算特征映射。Mercer定理给出了有效核函数的充要条件。

支持向量机:通过最大化间隔找到最优分类超平面。软间隔SVM通过参数C控制复杂度。支持向量是决定决策边界的关键训练点。

高斯过程:提供了灵活的贝叶斯非参数模型,天然给出预测的不确定性。与贝叶斯线性回归有深层联系。

计算挑战:核方法的训练复杂度为 $O(N^3)$,限制了其在大数据集上的应用。稀疏方法、随机特征等技术可以加速核方法。

核方法在机器学习中占据独特地位。它提供了优雅的理论框架,连接了线性代数和函数分析,同时在实际应用中表现出色。高斯过程作为核方法的贝叶斯版本,在现代贝叶斯优化和主动学习中发挥着核心作用。


五、思考与练习

思考题

为什么RBF核对应的特征空间是无穷维的?请尝试推导。

SVM的解是稀疏的(大部分alpha为零),这与Lasso的稀疏性有什么异同?

高斯过程的核函数选择如何影响模型的平滑性和泛化能力?

当训练数据量很大时,核方法会遇到什么计算瓶颈?有哪些解决方案?

核方法和神经网络有什么联系?神经切线核(NTK)理论说了什么?

编程练习

核函数比较:在多个数据集上比较线性核、多项式核和RBF核的分类性能,分析数据特性与核函数选择的关系。

高斯过程回归:实现高斯过程回归,使用不同的核函数(RBF、Matérn、周期核),观察它们对预测结果的影响。

随机特征近似:实现随机傅里叶特征近似RBF核,比较不同特征维度下近似精度和计算速度的权衡。


6/10核方法
0%