摘要:本章深入讲解支持向量机(SVM)的核心原理,从最大间隔分类的直观理解出发,完整推导原始问题与对偶问题的数学形式,详解SMO优化算法,揭示核技巧的数学本质,并通过实战案例展示SVM在图像分类中的应用。


环境声明

  • Python版本:Python 3.12+
  • 核心依赖:NumPy 1.24+, Scikit-learn 1.3+, Matplotlib 3.7+
  • 可选依赖:CVXOPT(用于自定义SVM求解)
  • 开发工具:PyCharm / VS Code / Jupyter Notebook
pip install numpy scikit-learn matplotlib seaborn cvxopt

学习目标

完成本章学习后,你将能够:

  1. 理解最大间隔分类的直观原理与支持向量的核心作用
  2. 独立完成SVM原始问题到对偶问题的完整数学推导
  3. 掌握KKT条件在SVM中的应用与几何解释
  4. 理解SMO算法的启发式选择策略与收敛性分析
  5. 深入理解核技巧的数学本质与Mercer条件
  6. 熟练运用Scikit-learn实现多分类SVM与支持向量回归
  7. 独立完成SVM图像分类实战项目

1. SVM直观理解

1.1 从感知机到最大间隔

支持向量机(Support Vector Machine, SVM)由Vapnik等人于1964年提出,是统计学习理论中最具代表性的算法之一。要理解SVM,我们需要从感知机说起。

感知机的局限

感知机通过寻找能够将两类样本分开的超平面来实现分类。然而,当数据线性可分时,存在无数个分离超平面,感知机只保证找到一个可行解,但不保证是最优解。

SVM的突破

SVM引入"最大间隔"原则,不仅要求正确分类,还要求分类间隔最大化。这一原则带来了两个关键优势:

  • 几何直观:间隔越大,分类器对噪声的容忍度越高
  • 理论保证:间隔与泛化误差界直接相关,间隔越大泛化性能越好

1.2 超平面与间隔的数学定义

超平面定义

在n维空间中,超平面由方程 wTx+b=0w^T x + b = 0wTx+b=0 定义,其中:

  • w∈Rnw \in \mathbb{R}^nwRn 是法向量,决定超平面的方向
  • b∈Rb \in \mathbb{R}bR 是偏置项,决定超平面到原点的距离

函数间隔与几何间隔

对于样本点 (xi,yi)(x_i, y_i)(xi,yi),其中 yi∈{−1,+1}y_i \in \{-1, +1\}yi{1,+1}

间隔类型定义特点
函数间隔γ^i=yi(wTxi+b)\hat{\gamma}_i = y_i(w^T x_i + b)γ^i=yi(wTxi+b)w,bw,bw,b缩放而变化
几何间隔γi=yi(wTxi+b)∣w∣\gamma_i = \frac{y_i(w^T x_i + b)}{|w|}γi=wyi(wTxi+b)具有尺度不变性

几何意义

几何间隔表示样本点到超平面的实际欧氏距离。对于分类正确的样本,几何间隔为正;分类错误则为负。

1.3 支持向量的概念

定义:支持向量是距离分离超平面最近的样本点,它们"支撑"着最大间隔边界。

关键性质

  1. 支持向量位于间隔边界上,满足 yi(wTxi+b)=1y_i(w^T x_i + b) = 1yi(wTxi+b)=1
  2. 最终决策函数仅依赖于支持向量:f(x)=∑i∈SVαiyixiTx+bf(x) = \sum_{i \in SV} \alpha_i y_i x_i^T x + bf(x)=iSVαiyixiTx+b
  3. 非支持向量的系数 αi=0\alpha_i = 0αi=0,对模型无贡献

直观比喻

想象在两类样本之间放置一块木板(超平面),支持向量就是那些"顶住"木板边缘的样本点。移动其他样本点(只要不超过间隔边界)不会改变木板的位置。

1.4 线性可分与软间隔

线性可分情况

当存在一个超平面能完美分离两类样本时,我们称之为线性可分。此时可以求解"硬间隔"SVM。

线性不可分情况

现实数据往往存在噪声或重叠,此时引入"软间隔":

  • 允许部分样本分类错误
  • 引入松弛变量 ξi≥0\xi_i \geq 0ξi0 度量违规程度
  • 在目标函数中添加惩罚项 C∑i=1nξiC \sum_{i=1}^n \xi_iCi=1nξi

参数 CCC 控制间隔宽度与分类错误的权衡:

  • CCC 较大:强调正确分类,间隔较窄,可能过拟合
  • CCC 较小:允许更多错误,间隔较宽,可能欠拟合

2. SVM原始问题与对偶问题推导

2.1 原始优化问题

硬间隔SVM的原始问题

min⁡w,b12∥w∥2s.t.yi(wTxi+b)≥1,i=1,2,...,n \begin{aligned} \min_{w, b} \quad & \frac{1}{2} \|w\|^2 \\ \text{s.t.} \quad & y_i(w^T x_i + b) \geq 1, \quad i = 1, 2, ..., n \end{aligned} w,bmins.t.21w2yi(wTxi+b)1,i=1,2,...,n

目标函数的几何解释

最小化 12∥w∥2\frac{1}{2}\|w\|^221w2 等价于最大化几何间隔 1∥w∥\frac{1}{\|w\|}w1。系数 12\frac{1}{2}21 是为了求导方便。

软间隔SVM的原始问题

min⁡w,b,ξ12∥w∥2+C∑i=1nξis.t.yi(wTxi+b)≥1−ξi,i=1,2,...,nξi≥0,i=1,2,...,n \begin{aligned} \min_{w, b, \xi} \quad & \frac{1}{2} \|w\|^2 + C \sum_{i=1}^n \xi_i \\ \text{s.t.} \quad & y_i(w^T x_i + b) \geq 1 - \xi_i, \quad i = 1, 2, ..., n \\ & \xi_i \geq 0, \quad i = 1, 2, ..., n \end{aligned} w,b,ξmins.t.21w2+Ci=1nξiyi(wTxi+b)1ξi,i=1,2,...,nξi0,i=1,2,...,n

2.2 拉格朗日函数构建

引入拉格朗日乘子 αi≥0\alpha_i \geq 0αi0μi≥0\mu_i \geq 0μi0,构建拉格朗日函数:

L(w,b,ξ,α,μ)=12∥w∥2+C∑i=1nξi−∑i=1nαi[yi(wTxi+b)−1+ξi]−∑i=1nμiξi \mathcal{L}(w, b, \xi, \alpha, \mu) = \frac{1}{2}\|w\|^2 + C\sum_{i=1}^n \xi_i - \sum_{i=1}^n \alpha_i[y_i(w^T x_i + b) - 1 + \xi_i] - \sum_{i=1}^n \mu_i \xi_i L(w,b,ξ,α,μ)=21w2+Ci=1nξii=1nαi[yi(wTxi+b)1+ξi]i=1nμiξi

各项含义

含义
12∣w∣2\frac{1}{2}|w|^221w2最大化间隔的目标
C∑ξiC\sum \xi_iCξi松弛变量的惩罚
−∑αi[...]-\sum \alpha_i[...]αi[...]不等式约束的惩罚(分类约束)
−∑μiξi-\sum \mu_i \xi_iμiξi非负约束的惩罚

2.3 对偶问题推导

步骤1:对原始变量求偏导并令其为零

www 求偏导:

∂L∂w=w−∑i=1nαiyixi=0⇒w=∑i=1nαiyixi \frac{\partial \mathcal{L}}{\partial w} = w - \sum_{i=1}^n \alpha_i y_i x_i = 0 \Rightarrow w = \sum_{i=1}^n \alpha_i y_i x_i wL=wi=1nαiyixi=0w=i=1nαiyixi

bbb 求偏导:

∂L∂b=−∑i=1nαiyi=0⇒∑i=1nαiyi=0 \frac{\partial \mathcal{L}}{\partial b} = -\sum_{i=1}^n \alpha_i y_i = 0 \Rightarrow \sum_{i=1}^n \alpha_i y_i = 0 bL=i=1nαiyi=0i=1nαiyi=0

ξi\xi_iξi 求偏导:

∂L∂ξi=C−αi−μi=0⇒αi+μi=C \frac{\partial \mathcal{L}}{\partial \xi_i} = C - \alpha_i - \mu_i = 0 \Rightarrow \alpha_i + \mu_i = C ξiL=Cαiμi=0αi+μi=C

步骤2:回代拉格朗日函数

将上述结果代入原拉格朗日函数:

L=12∑i=1n∑j=1nαiαjyiyjxiTxj+C∑i=1nξi−∑i=1nαiyi(∑j=1nαjyjxjT)xi−b∑i=1nαiyi+∑i=1nαi−∑i=1nαiξi−∑i=1nμiξi=−12∑i=1n∑j=1nαiαjyiyjxiTxj+∑i=1nαi \begin{aligned} \mathcal{L} &= \frac{1}{2}\sum_{i=1}^n \sum_{j=1}^n \alpha_i \alpha_j y_i y_j x_i^T x_j + C\sum_{i=1}^n \xi_i \\ &\quad - \sum_{i=1}^n \alpha_i y_i \left(\sum_{j=1}^n \alpha_j y_j x_j^T\right) x_i - b\sum_{i=1}^n \alpha_i y_i + \sum_{i=1}^n \alpha_i - \sum_{i=1}^n \alpha_i \xi_i - \sum_{i=1}^n \mu_i \xi_i \\ &= -\frac{1}{2}\sum_{i=1}^n \sum_{j=1}^n \alpha_i \alpha_j y_i y_j x_i^T x_j + \sum_{i=1}^n \alpha_i \end{aligned} L=21i=1nj=1nαiαjyiyjxiTxj+Ci=1nξii=1nαiyi(j=1nαjyjxjT)xibi=1nαiyi+i=1nαii=1nαiξii=1nμiξi=21i=1nj=1nαiαjyiyjxiTxj+i=1nαi

步骤3:得到对偶问题

max⁡α∑i=1nαi−12∑i=1n∑j=1nαiαjyiyjxiTxjs.t.∑i=1nαiyi=00≤αi≤C,i=1,2,...,n \begin{aligned} \max_{\alpha} \quad & \sum_{i=1}^n \alpha_i - \frac{1}{2}\sum_{i=1}^n \sum_{j=1}^n \alpha_i \alpha_j y_i y_j x_i^T x_j \\ \text{s.t.} \quad & \sum_{i=1}^n \alpha_i y_i = 0 \\ & 0 \leq \alpha_i \leq C, \quad i = 1, 2, ..., n \end{aligned} αmaxs.t.i=1nαi21i=1nj=1nαiαjyiyjxiTxji=1nαiyi=00αiC,i=1,2,...,n

2.4 KKT条件分析

KKT条件是原始问题与对偶问题最优解的充要条件:

  1. 平稳性条件w=∑i=1nαiyixiw = \sum_{i=1}^n \alpha_i y_i x_iw=i=1nαiyixi∑i=1nαiyi=0\sum_{i=1}^n \alpha_i y_i = 0i=1nαiyi=0

  2. 原始可行性yi(wTxi+b)≥1−ξiy_i(w^T x_i + b) \geq 1 - \xi_iyi(wTxi+b)1ξiξi≥0\xi_i \geq 0ξi0

  3. 对偶可行性αi≥0\alpha_i \geq 0αi0μi≥0\mu_i \geq 0μi0

  4. 互补松弛条件

    • αi[yi(wTxi+b)−1+ξi]=0\alpha_i[y_i(w^T x_i + b) - 1 + \xi_i] = 0αi[yi(wTxi+b)1+ξi]=0
    • μiξi=0\mu_i \xi_i = 0μiξi=0

互补松弛条件的深入分析

αi+μi=C\alpha_i + \mu_i = Cαi+μi=Cμiξi=0\mu_i \xi_i = 0μiξi=0,可得三种情况:

情况条件样本位置含义
αi=0\alpha_i = 0αi=0yi(wTxi+b)>1y_i(w^T x_i + b) > 1yi(wTxi+b)>1间隔边界外非支持向量
0<αi<C0 < \alpha_i < C0<αi<Cyi(wTxi+b)=1y_i(w^T x_i + b) = 1yi(wTxi+b)=1间隔边界上自由支持向量
αi=C\alpha_i = Cαi=Cyi(wTxi+b)<1y_i(w^T x_i + b) < 1yi(wTxi+b)<1间隔边界内或错分边界支持向量

偏置项 bbb 的计算

对于自由支持向量(0<αi<C0 < \alpha_i < C0<αi<C),有:

b=yi−∑j=1nαjyjxjTxi b = y_i - \sum_{j=1}^n \alpha_j y_j x_j^T x_i b=yij=1nαjyjxjTxi

实际计算中通常取所有自由支持向量的平均值以提高数值稳定性。

2.5 决策函数

求解得到最优 α∗\alpha^*α 后,决策函数为:

f(x)=sign(∑i=1nαi∗yixiTx+b∗) f(x) = \text{sign}\left(\sum_{i=1}^n \alpha_i^* y_i x_i^T x + b^*\right) f(x)=sign(i=1nαiyixiTx+b)

由于大多数 αi=0\alpha_i = 0αi=0,求和只需针对支持向量进行,大大提高了预测效率。


3. SMO算法详解

3.1 SMO算法概述

序列最小优化(Sequential Minimal Optimization, SMO)由Platt于1998年提出,是求解SVM对偶问题的高效算法。

核心思想

  • 每次只优化两个拉格朗日乘子,将大问题分解为一系列最小子问题
  • 由于约束 ∑αiyi=0\sum \alpha_i y_i = 0αiyi=0,每次必须同时更新两个乘子
  • 解析求解两个变量的二次规划问题,避免调用数值优化库

3.2 两个变量的优化问题

假设选择变量 α1\alpha_1α1α2\alpha_2α2 进行优化,其他变量固定。约束条件为:

α1y1+α2y2=−∑i=3nαiyi=ζ(常数) \alpha_1 y_1 + \alpha_2 y_2 = -\sum_{i=3}^n \alpha_i y_i = \zeta \text{(常数)} α1y1+α2y2=i=3nαiyi=ζ(常数)

边界约束

  • y1≠y2y_1 \neq y_2y1=y2max⁡(0,α2−α1)≤α2new≤min⁡(C,C+α2−α1)\max(0, \alpha_2 - \alpha_1) \leq \alpha_2^{new} \leq \min(C, C + \alpha_2 - \alpha_1)max(0,α2α1)α2newmin(C,C+α2α1)
  • y1=y2y_1 = y_2y1=y2max⁡(0,α2+α1−C)≤α2new≤min⁡(C,α2+α1)\max(0, \alpha_2 + \alpha_1 - C) \leq \alpha_2^{new} \leq \min(C, \alpha_2 + \alpha_1)max(0,α2+α1C)α2newmin(C,α2+α1)

3.3 无约束最优解推导

定义预测误差:Ei=f(xi)−yi=∑j=1nαjyjK(xj,xi)+b−yiE_i = f(x_i) - y_i = \sum_{j=1}^n \alpha_j y_j K(x_j, x_i) + b - y_iEi=f(xi)yi=j=1nαjyjK(xj,xi)+byi

η=K(x1,x1)+K(x2,x2)−2K(x1,x2)\eta = K(x_1, x_1) + K(x_2, x_2) - 2K(x_1, x_2)η=K(x1,x1)+K(x2,x2)2K(x1,x2),则:

α2new,unc=α2old+y2(E1−E2)η \alpha_2^{new,unc} = \alpha_2^{old} + \frac{y_2(E_1 - E_2)}{\eta} α2new,unc=α2old+ηy2(E1E2)

裁剪到可行域

α2new={H,if α2new,unc>Hα2new,unc,if L≤α2new,unc≤HL,if α2new,unc<L \alpha_2^{new} = \begin{cases} H, & \text{if } \alpha_2^{new,unc} > H \\ \alpha_2^{new,unc}, & \text{if } L \leq \alpha_2^{new,unc} \leq H \\ L, & \text{if } \alpha_2^{new,unc} < L \end{cases} α2new=H,α2new,unc,L,if α2new,unc>Hif Lα2new,uncHif α2new,unc<L

然后更新 α1\alpha_1α1

α1new=α1old+y1y2(α2old−α2new) \alpha_1^{new} = \alpha_1^{old} + y_1 y_2 (\alpha_2^{old} - \alpha_2^{new}) α1new=α1old+y1y2(α2oldα2new)

3.4 启发式变量选择策略

外层循环:选择第一个变量

  1. 首先遍历所有样本,寻找违反KKT条件的样本
  2. 若未找到,遍历整个训练集
  3. 若仍未找到,算法终止

内层循环:选择第二个变量

目标是使 ∣E1−E2∣|E_1 - E_2|E1E2 最大化,这样更新步长最大。具体策略:

  • E1>0E_1 > 0E1>0,选择具有最小 EiE_iEi 的样本
  • E1<0E_1 < 0E1<0,选择具有最大 EiE_iEi 的样本

缓存机制

维护误差缓存,存储所有非边界样本的 EiE_iEi 值,避免重复计算。

3.5 偏置项更新

更新 α\alphaα 后,需要重新计算 bbb

0<α1new<C0 < \alpha_1^{new} < C0<α1new<C

b1new=−E1−y1K(x1,x1)(α1new−α1old)−y2K(x2,x1)(α2new−α2old)+bold b_1^{new} = -E_1 - y_1 K(x_1, x_1)(\alpha_1^{new} - \alpha_1^{old}) - y_2 K(x_2, x_1)(\alpha_2^{new} - \alpha_2^{old}) + b^{old} b1new=E1y1K(x1,x1)(α1newα1old)y2K(x2,x1)(α2newα2old)+bold

0<α2new<C0 < \alpha_2^{new} < C0<α2new<C,类似计算 b2newb_2^{new}b2new

若两者都在边界内,取平均值:bnew=b1new+b2new2b^{new} = \frac{b_1^{new} + b_2^{new}}{2}bnew=2b1new+b2new

3.6 SMO算法伪代码

输入:训练集 {(x_i, y_i)},精度 ε,最大迭代次数 max_iter
输出:α, b

初始化 α = 0, b = 0
计算所有样本的 E_i

while 未达到收敛条件 and 迭代次数 < max_iter:
    # 外层循环:选择第一个变量
    for i in range(n):
        if α_i 违反 KKT 条件:
            # 内层循环:选择第二个变量
            选择 j 使得 |E_i - E_j| 最大
            
            # 求解两个变量的QP问题
            计算 L, H
            计算 η
            if η <= 0: continue
            
            计算 α_j^new,unc
            裁剪得到 α_j^new
            计算 α_i^new
            
            # 更新阈值 b
            更新 b
            
            # 更新误差缓存
            更新 E_i, E_j

3.7 SMO的收敛性

SMO算法保证收敛到全局最优解,因为:

  1. 每次迭代目标函数值不减
  2. 目标函数有上界(对偶问题的最优值)
  3. 算法在有限步内收敛

实际应用中,SMO通常比通用QP求解器快几个数量级,特别是在稀疏数据集上。


4. 核函数原理

4.1 非线性分类的动机

线性不可分问题

许多实际问题中,两类样本在原始特征空间中无法被超平面分离。例如,异或(XOR)问题在二维平面上是线性不可分的。

解决方案:特征映射

将数据从原始空间映射到高维特征空间,使其在高维空间中线性可分。

示例

对于二维数据 x=(x1,x2)x = (x_1, x_2)x=(x1,x2),定义映射:

ϕ(x)=(x1,x2,x12+x22) \phi(x) = (x_1, x_2, x_1^2 + x_2^2) ϕ(x)=(x1,x2,x12+x22)

这样,原始空间中的圆边界 x12+x22=r2x_1^2 + x_2^2 = r^2x12+x22=r2 就变成了三维空间中的超平面。

4.2 核技巧的核心思想

显式映射的问题

  • 高维特征空间可能维度极高甚至无限维
  • 显式计算 ϕ(x)\phi(x)ϕ(x) 计算量巨大
  • 存储高维特征向量内存开销大

核技巧的突破

注意到对偶问题中只涉及样本间的内积 xiTxjx_i^T x_jxiTxj。如果我们能直接计算高维空间中的内积而不显式构造映射:

K(xi,xj)=ϕ(xi)Tϕ(xj) K(x_i, x_j) = \phi(x_i)^T \phi(x_j) K(xi,xj)=ϕ(xi)Tϕ(xj)

这就是核技巧(Kernel Trick)的核心。

4.3 常用核函数及其推导

线性核(Linear Kernel)

K(x,z)=xTz K(x, z) = x^T z K(x,z)=xTz

对应特征映射:ϕ(x)=x\phi(x) = xϕ(x)=x(恒等映射)

适用场景:特征维度高、数据量大的线性可分问题

多项式核(Polynomial Kernel)

K(x,z)=(γxTz+r)d K(x, z) = (\gamma x^T z + r)^d K(x,z)=(γxTz+r)d

其中:

  • γ\gammaγ:缩放系数
  • rrr:常数项(偏置)
  • ddd:多项式次数

特征映射推导(以 d=2,r=0d=2, r=0d=2,r=0 为例):

K(x,z)=(xTz)2=(∑i=1nxizi)2=∑i=1nxi2zi2+∑i=1n∑j=i+1n2xixjzizj \begin{aligned} K(x, z) &= (x^T z)^2 = \left(\sum_{i=1}^n x_i z_i\right)^2 \\ &= \sum_{i=1}^n x_i^2 z_i^2 + \sum_{i=1}^n \sum_{j=i+1}^n 2x_i x_j z_i z_j \end{aligned} K(x,z)=(xTz)2=(i=1nxizi)2=i=1nxi2zi2+i=1nj=i+1n2xixjzizj

对应特征映射:

ϕ(x)=(x12,x22,...,xn2,2x1x2,2x1x3,...,2xn−1xn) \phi(x) = (x_1^2, x_2^2, ..., x_n^2, \sqrt{2}x_1 x_2, \sqrt{2}x_1 x_3, ..., \sqrt{2}x_{n-1} x_n) ϕ(x)=(x12,x22,...,xn2,2x1x2,2x1x3,...,2xn1xn)

特征维度从 nnn 增加到 n(n+1)2\frac{n(n+1)}{2}2n(n+1)

高斯RBF核(Radial Basis Function)

K(x,z)=exp⁡(−∥x−z∥22σ2)=exp⁡(−γ∥x−z∥2) K(x, z) = \exp\left(-\frac{\|x - z\|^2}{2\sigma^2}\right) = \exp(-\gamma \|x - z\|^2) K(x,z)=exp(2σ2xz2)=exp(γxz2)

其中 γ=12σ2\gamma = \frac{1}{2\sigma^2}γ=2σ21

特征映射推导

利用泰勒展开:

exp⁡(−γ∥x−z∥2)=exp⁡(−γ∥x∥2)exp⁡(−γ∥z∥2)exp⁡(2γxTz) \exp(-\gamma \|x - z\|^2) = \exp(-\gamma \|x\|^2) \exp(-\gamma \|z\|^2) \exp(2\gamma x^T z) exp(γxz2)=exp(γx2)exp(γz2)exp(2γxTz)

展开指数项:

exp⁡(2γxTz)=∑k=0∞(2γ)kk!(xTz)k \exp(2\gamma x^T z) = \sum_{k=0}^{\infty} \frac{(2\gamma)^k}{k!} (x^T z)^k exp(2γxTz)=k=0k!(2γ)k(xTz)k

因此,RBF核对应无限维的特征映射!

Sigmoid核

K(x,z)=tanh⁡(γxTz+r) K(x, z) = \tanh(\gamma x^T z + r) K(x,z)=tanh(γxTz+r)

这个核函数与神经网络中的激活函数类似,在特定场景下表现良好。

4.4 核函数对比

核函数表达式参数适用场景
线性核K(x,z)=xTzK(x,z) = x^T zK(x,z)=xTz高维数据、文本分类
多项式核(γxTz+r)d(\gamma x^T z + r)^d(γxTz+r)dγ,r,d\gamma, r, dγ,r,d图像处理、多项式特征
RBF核exp⁡(−γ∣x−z∣2)\exp(-\gamma |x-z|^2)exp(γxz2)γ\gammaγ通用场景、非线性边界
Sigmoid核tanh⁡(γxTz+r)\tanh(\gamma x^T z + r)tanh(γxTz+r)γ,r\gamma, rγ,r神经网络类似场景

参数选择建议

  • RBF核的 γ\gammaγ
    • 过小:模型过于简单,欠拟合
    • 过大:模型过于复杂,过拟合
    • 通常通过交叉验证选择

5. 核技巧与核矩阵

5.1 核矩阵的定义与性质

定义

对于训练集 {x1,x2,...,xn}\{x_1, x_2, ..., x_n\}{x1,x2,...,xn},核矩阵(Gram矩阵)K∈Rn×nK \in \mathbb{R}^{n \times n}KRn×n 定义为:

Kij=K(xi,xj)=ϕ(xi)Tϕ(xj) K_{ij} = K(x_i, x_j) = \phi(x_i)^T \phi(x_j) Kij=K(xi,xj)=ϕ(xi)Tϕ(xj)

性质

  1. 对称性Kij=KjiK_{ij} = K_{ji}Kij=Kji
  2. 半正定性:对于任意向量 c∈Rnc \in \mathbb{R}^ncRncTKc≥0c^T K c \geq 0cTKc0

证明半正定性

cTKc=∑i=1n∑j=1ncicjK(xi,xj)=∑i=1n∑j=1ncicjϕ(xi)Tϕ(xj)=∥∑i=1nciϕ(xi)∥2≥0 c^T K c = \sum_{i=1}^n \sum_{j=1}^n c_i c_j K(x_i, x_j) = \sum_{i=1}^n \sum_{j=1}^n c_i c_j \phi(x_i)^T \phi(x_j) = \left\|\sum_{i=1}^n c_i \phi(x_i)\right\|^2 \geq 0 cTKc=i=1nj=1ncicjK(xi,xj)=i=1nj=1ncicjϕ(xi)Tϕ(xj)=i=1nciϕ(xi)20

5.2 Mercer条件

Mercer定理

函数 K(x,z)K(x, z)K(x,z) 是有效核函数(即存在特征映射 ϕ\phiϕ 使得 K(x,z)=ϕ(x)Tϕ(z)K(x, z) = \phi(x)^T \phi(z)K(x,z)=ϕ(x)Tϕ(z))的充要条件是:

  1. K(x,z)K(x, z)K(x,z) 对称:K(x,z)=K(z,x)K(x, z) = K(z, x)K(x,z)=K(z,x)
  2. K(x,z)K(x, z)K(x,z) 是半正定的:对于任意平方可积函数 ggg,有

∫∫K(x,z)g(x)g(z)dxdz≥0 \int \int K(x, z) g(x) g(z) dx dz \geq 0 ∫∫K(x,z)g(x)g(z)dxdz0

Mercer条件的意义

  • 保证优化问题是凸的,存在全局最优解
  • 确保核矩阵可分解,数值计算稳定
  • 为构造新核函数提供理论基础

5.3 核函数的构造

基本运算封闭性

K1,K2K_1, K_2K1,K2 是有效核函数,则以下也是有效核函数:

运算结果核函数
数乘cK1(x,z)c K_1(x, z)cK1(x,z)c>0c > 0c>0
加法K1(x,z)+K2(x,z)K_1(x, z) + K_2(x, z)K1(x,z)+K2(x,z)
乘法K1(x,z)⋅K2(x,z)K_1(x, z) \cdot K_2(x, z)K1(x,z)K2(x,z)
函数复合K(x,z)=f(x)f(z)K1(x,z)K(x, z) = f(x) f(z) K_1(x, z)K(x,z)=f(x)f(z)K1(x,z)
极限有效核函数序列的极限

构造新核函数的示例

假设 K1K_1K1 是RBF核,K2K_2K2 是多项式核,则:

K(x,z)=K1(x,z)+K2(x,z) K(x, z) = K_1(x, z) + K_2(x, z) K(x,z)=K1(x,z)+K2(x,z)

也是一个有效的核函数,结合了两种核的特点。

5.4 核方法在SVM中的应用

引入核函数后,对偶问题变为:

max⁡α∑i=1nαi−12∑i=1n∑j=1nαiαjyiyjK(xi,xj)s.t.∑i=1nαiyi=00≤αi≤C \begin{aligned} \max_{\alpha} \quad & \sum_{i=1}^n \alpha_i - \frac{1}{2}\sum_{i=1}^n \sum_{j=1}^n \alpha_i \alpha_j y_i y_j K(x_i, x_j) \\ \text{s.t.} \quad & \sum_{i=1}^n \alpha_i y_i = 0 \\ & 0 \leq \alpha_i \leq C \end{aligned} αmaxs.t.i=1nαi21i=1nj=1nαiαjyiyjK(xi,xj)i=1nαiyi=00αiC

决策函数

f(x)=sign(∑i=1nαi∗yiK(xi,x)+b∗) f(x) = \text{sign}\left(\sum_{i=1}^n \alpha_i^* y_i K(x_i, x) + b^*\right) f(x)=sign(i=1nαiyiK(xi,x)+b)

关键观察

  • 训练过程只需要计算核矩阵 KKK
  • 预测时需要计算新样本与支持向量的核函数值
  • 完全不需要显式知道特征映射 ϕ\phiϕ 的形式

6. 多分类SVM与SVR

6.1 多分类策略

SVM本质上是二分类器,扩展到多分类有两种主要策略:

One-vs-One(OvO)

  • 对于 kkk 个类别,训练 k(k−1)2\frac{k(k-1)}{2}2k(k1) 个分类器
  • 每个分类器区分一对类别
  • 预测时投票,得票最多的类别为最终预测

优点

  • 每个子问题训练样本少,计算效率高
  • 适用于类别数较少的情况

缺点

  • 分类器数量随类别数平方增长
  • 可能存在投票平局

One-vs-Rest(OvR)

  • 对于 kkk 个类别,训练 kkk 个分类器
  • 每个分类器将一个类别与所有其他类别区分
  • 预测时选择输出值最大的类别

优点

  • 分类器数量线性增长
  • 决策边界清晰

缺点

  • 每个分类器面对不平衡数据
  • 训练样本量大

策略对比

特性One-vs-OneOne-vs-Rest
分类器数量k(k−1)/2k(k-1)/2k(k1)/2kkk
每个分类器训练样本较少全部
预测速度较慢较快
适用场景类别数少类别数多

Scikit-learn默认使用OvO策略,可以通过参数调整。

6.2 支持向量回归(SVR)

基本思想

SVR扩展了SVM的思想到回归问题。不同于分类问题中寻找最大间隔超平面,SVR寻找能够"容纳"最多样本的"管道"。

ε-不敏感损失函数

Lϵ(y,f(x))={0,if ∣y−f(x)∣≤ϵ∣y−f(x)∣−ϵ,otherwise L_\epsilon(y, f(x)) = \begin{cases} 0, & \text{if } |y - f(x)| \leq \epsilon \\ |y - f(x)| - \epsilon, & \text{otherwise} \end{cases} Lϵ(y,f(x))={0,yf(x)ϵ,if yf(x)ϵotherwise

原始优化问题

min⁡w,b,ξ,ξ∗12∥w∥2+C∑i=1n(ξi+ξi∗)s.t.yi−wTxi−b≤ϵ+ξiwTxi+b−yi≤ϵ+ξi∗ξi,ξi∗≥0 \begin{aligned} \min_{w, b, \xi, \xi^*} \quad & \frac{1}{2}\|w\|^2 + C \sum_{i=1}^n (\xi_i + \xi_i^*) \\ \text{s.t.} \quad & y_i - w^T x_i - b \leq \epsilon + \xi_i \\ & w^T x_i + b - y_i \leq \epsilon + \xi_i^* \\ & \xi_i, \xi_i^* \geq 0 \end{aligned} w,b,ξ,ξmins.t.21w2+Ci=1n(ξi+ξi)yiwTxibϵ+ξiwTxi+byiϵ+ξiξi,ξi0

对偶问题

max⁡α,α∗−12∑i,j(αi−αi∗)(αj−αj∗)K(xi,xj)−ϵ∑i(αi+αi∗)+∑iyi(αi−αi∗)s.t.∑i(αi−αi∗)=00≤αi,αi∗≤C \begin{aligned} \max_{\alpha, \alpha^*} \quad & -\frac{1}{2}\sum_{i,j}(\alpha_i - \alpha_i^*)(\alpha_j - \alpha_j^*)K(x_i, x_j) \\ & - \epsilon\sum_i(\alpha_i + \alpha_i^*) + \sum_i y_i(\alpha_i - \alpha_i^*) \\ \text{s.t.} \quad & \sum_i(\alpha_i - \alpha_i^*) = 0 \\ & 0 \leq \alpha_i, \alpha_i^* \leq C \end{aligned} α,αmaxs.t.21i,j(αiαi)(αjαj)K(xi,xj)ϵi(αi+αi)+iyi(αiαi)i(αiαi)=00αi,αiC

决策函数

f(x)=∑i=1n(αi−αi∗)K(xi,x)+b f(x) = \sum_{i=1}^n (\alpha_i - \alpha_i^*) K(x_i, x) + b f(x)=i=1n(αiαi)K(xi,x)+b

支持向量的定义

在SVR中,满足 ∣yi−f(xi)∣≥ϵ|y_i - f(x_i)| \geq \epsilonyif(xi)ϵ 的样本是支持向量,它们位于管道的边界之外。

6.3 SVR参数调优

参数作用调优建议
C惩罚系数控制模型复杂度,通过交叉验证选择
ε不敏感区域宽度较大值使模型更平滑,较小值更精确
kernel核函数类型根据数据特性选择
γRBF核参数影响单个样本的影响范围

7. 实战案例:SVM可视化与图像分类

7.1 案例概述

本案例包含三个部分:

  1. 二维数据SVM决策边界可视化
  2. 不同核函数效果对比
  3. 手写数字图像分类

7.2 环境准备与数据生成

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.svm import SVC, SVR
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.metrics import accuracy_score, classification_report
from sklearn.decomposition import PCA
import warnings
warnings.filterwarnings('ignore')

# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

# 生成示例数据:月牙形数据(非线性可分)
def make_moons_data(n_samples=300, noise=0.3, random_state=42):
    """
    生成月牙形非线性可分数据
    
    参数:
        n_samples: 样本总数
        noise: 噪声水平
        random_state: 随机种子
    
    返回:
        X: 特征矩阵 (n_samples, 2)
        y: 标签向量 (n_samples,)
    """
    X, y = datasets.make_moons(
        n_samples=n_samples, 
        noise=noise, 
        random_state=random_state
    )
    return X, y

# 生成同心圆数据
def make_circles_data(n_samples=300, noise=0.1, factor=0.3, random_state=42):
    """
    生成同心圆数据
    
    参数:
        n_samples: 样本总数
        noise: 噪声水平
        factor: 内外圆半径比例
        random_state: 随机种子
    
    返回:
        X: 特征矩阵
        y: 标签向量
    """
    X, y = datasets.make_circles(
        n_samples=n_samples,
        noise=noise,
        factor=factor,
        random_state=random_state
    )
    return X, y

# 生成数据
X_moons, y_moons = make_moons_data()
X_circles, y_circles = make_circles_data()

print("月牙数据形状:", X_moons.shape)
print("同心圆数据形状:", X_circles.shape)

7.3 SVM决策边界可视化

def plot_decision_boundary(X, y, model, title='SVM Decision Boundary', ax=None):
    """
    绘制SVM决策边界
    
    参数:
        X: 特征数据 (n_samples, 2)
        y: 标签数据 (n_samples,)
        model: 训练好的SVM模型
        title: 图表标题
        ax: matplotlib轴对象
    """
    if ax is None:
        fig, ax = plt.subplots(figsize=(10, 8))
    
    # 创建网格
    h = 0.02  # 网格步长
    x_min, x_max = X[:, 0].min() - 0.5, X[:, 0].max() + 0.5
    y_min, y_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                         np.arange(y_min, y_max, h))
    
    # 预测网格点
    Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    
    # 绘制决策区域
    ax.contourf(xx, yy, Z, alpha=0.4, cmap=plt.cm.RdYlBu)
    
    # 绘制决策边界和间隔边界
    if hasattr(model, 'decision_function'):
        Z_contour = model.decision_function(np.c_[xx.ravel(), yy.ravel()])
        Z_contour = Z_contour.reshape(xx.shape)
        ax.contour(xx, yy, Z_contour, levels=[-1, 0, 1], 
                   colors='k', linestyles=['--', '-', '--'], linewidths=1)
    
    # 绘制数据点
    scatter = ax.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.RdYlBu, 
                        edgecolors='k', s=50)
    
    # 标记支持向量
    support_vectors = model.support_vectors_
    ax.scatter(support_vectors[:, 0], support_vectors[:, 1], 
              s=200, facecolors='none', edgecolors='k', 
              linewidths=1.5, label='Support Vectors')
    
    ax.set_xlabel('Feature 1')
    ax.set_ylabel('Feature 2')
    ax.set_title(title)
    ax.legend()
    
    return ax

# 使用不同核函数训练SVM并可视化
kernels = ['linear', 'poly', 'rbf', 'sigmoid']
C = 1.0

fig, axes = plt.subplots(2, 2, figsize=(15, 12))
axes = axes.ravel()

for idx, kernel in enumerate(kernels):
    # 训练SVM模型
    svm_model = SVC(kernel=kernel, C=C, gamma='scale', random_state=42)
    svm_model.fit(X_moons, y_moons)
    
    # 计算准确率
    accuracy = svm_model.score(X_moons, y_moons)
    n_support = len(svm_model.support_vectors_)
    
    # 绘制决策边界
    title = f'Kernel: {kernel.upper()}\nAccuracy: {accuracy:.3f}, Support Vectors: {n_support}'
    plot_decision_boundary(X_moons, y_moons, svm_model, title, axes[idx])

plt.tight_layout()
plt.savefig('svm_kernels_comparison.png', dpi=150, bbox_inches='tight')
plt.show()

print("不同核函数对比图已保存")

7.4 超参数调优

def tune_svm_hyperparameters(X, y):
    """
    使用网格搜索调优SVM超参数
    
    参数:
        X: 特征数据
        y: 标签数据
    
    返回:
        best_model: 最优模型
        best_params: 最优参数
    """
    # 划分训练集和测试集
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=42, stratify=y
    )
    
    # 数据标准化
    scaler = StandardScaler()
    X_train_scaled = scaler.fit_transform(X_train)
    X_test_scaled = scaler.transform(X_test)
    
    # 定义参数网格
    param_grid = {
        'C': [0.1, 1, 10, 100],
        'gamma': ['scale', 'auto', 0.001, 0.01, 0.1, 1],
        'kernel': ['rbf', 'poly', 'sigmoid']
    }
    
    # 网格搜索
    grid_search = GridSearchCV(
        SVC(random_state=42),
        param_grid,
        cv=5,
        scoring='accuracy',
        n_jobs=-1,
        verbose=1
    )
    
    grid_search.fit(X_train_scaled, y_train)
    
    # 最优模型评估
    best_model = grid_search.best_estimator_
    y_pred = best_model.predict(X_test_scaled)
    test_accuracy = accuracy_score(y_test, y_pred)
    
    print("=" * 50)
    print("最优参数:", grid_search.best_params_)
    print("交叉验证最优得分:", grid_search.best_score_)
    print("测试集准确率:", test_accuracy)
    print("=" * 50)
    print("\n分类报告:")
    print(classification_report(y_test, y_pred))
    
    return best_model, grid_search.best_params_, scaler

# 在月牙数据上调优
print("月牙数据超参数调优:")
best_model_moons, best_params_moons, scaler_moons = tune_svm_hyperparameters(X_moons, y_moons)

7.5 手写数字分类实战

def digit_classification_demo():
    """
    手写数字分类实战演示
    使用sklearn内置的digits数据集
    """
    # 加载手写数字数据集
    digits = datasets.load_digits()
    X, y = digits.data, digits.target
    
    print("数据集信息:")
    print(f"  样本数量: {X.shape[0]}")
    print(f"  特征维度: {X.shape[1]} (8x8图像)")
    print(f"  类别数量: {len(np.unique(y))} (0-9)")
    
    # 划分数据集
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=42, stratify=y
    )
    
    # 数据标准化
    scaler = StandardScaler()
    X_train_scaled = scaler.fit_transform(X_train)
    X_test_scaled = scaler.transform(X_test)
    
    # 使用PCA降维可视化
    pca = PCA(n_components=2)
    X_pca = pca.fit_transform(X_train_scaled)
    
    # 可视化PCA后的数据分布
    plt.figure(figsize=(12, 5))
    
    plt.subplot(1, 2, 1)
    scatter = plt.scatter(X_pca[:, 0], X_pca[:, 1], c=y_train, 
                         cmap='tab10', alpha=0.6)
    plt.colorbar(scatter, label='Digit')
    plt.xlabel('First Principal Component')
    plt.ylabel('Second Principal Component')
    plt.title('Digits Dataset (PCA 2D)')
    
    # 训练SVM分类器
    print("\n训练SVM分类器...")
    svm_digits = SVC(kernel='rbf', C=10, gamma=0.001, random_state=42)
    svm_digits.fit(X_train_scaled, y_train)
    
    # 预测与评估
    y_pred = svm_digits.predict(X_test_scaled)
    accuracy = accuracy_score(y_test, y_pred)
    
    print(f"\n测试集准确率: {accuracy:.4f}")
    print(f"支持向量总数: {svm_digits.support_.shape[0]}")
    print(f"每类支持向量数: {svm_digits.n_support_}")
    
    # 可视化一些预测结果
    plt.subplot(1, 2, 2)
    
    # 随机选择16个测试样本展示
    n_samples = 16
    indices = np.random.choice(len(X_test), n_samples, replace=False)
    
    for i, idx in enumerate(indices):
        plt.subplot(4, 8, i + 1 + 8)
        plt.imshow(X_test[idx].reshape(8, 8), cmap='gray')
        pred = y_pred[idx]
        true = y_test[idx]
        color = 'green' if pred == true else 'red'
        plt.title(f'P:{pred}\nT:{true}', color=color, fontsize=8)
        plt.axis('off')
    
    plt.suptitle('SVM Digit Classification Results')
    plt.tight_layout()
    plt.savefig('svm_digit_classification.png', dpi=150, bbox_inches='tight')
    plt.show()
    
    # 详细分类报告
    print("\n详细分类报告:")
    print(classification_report(y_test, y_pred))
    
    return svm_digits, accuracy

# 运行数字分类演示
print("手写数字分类实战:")
digit_model, digit_accuracy = digit_classification_demo()

7.6 支持向量回归示例

def svr_regression_demo():
    """
    支持向量回归示例
    使用正弦波数据演示SVR的拟合效果
    """
    # 生成带噪声的正弦波数据
    np.random.seed(42)
    X = np.sort(5 * np.random.rand(100, 1), axis=0)
    y = np.sin(X).ravel()
    y[::5] += 3 * (0.5 - np.random.rand(20))  # 添加噪声
    
    # 训练不同参数的SVR模型
    svr_rbf = SVR(kernel='rbf', C=100, gamma=0.1, epsilon=0.1)
    svr_poly = SVR(kernel='poly', C=100, degree=3, epsilon=0.1)
    svr_linear = SVR(kernel='linear', C=100, epsilon=0.1)
    
    # 拟合模型
    svr_rbf.fit(X, y)
    svr_poly.fit(X, y)
    svr_linear.fit(X, y)
    
    # 预测
    X_test = np.arange(0, 5, 0.01)[:, np.newaxis]
    y_rbf = svr_rbf.predict(X_test)
    y_poly = svr_poly.predict(X_test)
    y_linear = svr_linear.predict(X_test)
    
    # 可视化
    plt.figure(figsize=(15, 5))
    
    models = [
        (y_rbf, 'RBF kernel', 'red'),
        (y_poly, 'Polynomial kernel', 'green'),
        (y_linear, 'Linear kernel', 'blue')
    ]
    
    for idx, (y_pred, title, color) in enumerate(models):
        plt.subplot(1, 3, idx + 1)
        plt.scatter(X, y, color='darkorange', label='Data', s=30)
        plt.plot(X_test, y_pred, color=color, lw=2, label='SVR')
        plt.plot(X_test, np.sin(X_test), color='navy', lw=1, 
                linestyle='--', label='True function')
        plt.xlabel('X')
        plt.ylabel('y')
        plt.title(title)
        plt.legend()
        plt.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.savefig('svr_comparison.png', dpi=150, bbox_inches='tight')
    plt.show()
    
    # 计算MSE
    from sklearn.metrics import mean_squared_error
    print("\n各模型MSE:")
    print(f"  RBF: {mean_squared_error(np.sin(X_test).ravel(), y_rbf):.4f}")
    print(f"  Poly: {mean_squared_error(np.sin(X_test).ravel(), y_poly):.4f}")
    print(f"  Linear: {mean_squared_error(np.sin(X_test).ravel(), y_linear):.4f}")

# 运行SVR演示
print("\n支持向量回归演示:")
svr_regression_demo()

7.7 完整代码汇总

"""
SVM完整实战代码
包含:数据生成、可视化、超参数调优、图像分类、回归
"""

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.svm import SVC, SVR
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.metrics import accuracy_score, classification_report, mean_squared_error
from sklearn.decomposition import PCA
import warnings
warnings.filterwarnings('ignore')

# 设置随机种子确保可复现
np.random.seed(42)

class SVMPracticalGuide:
    """SVM实战指南类"""
    
    def __init__(self):
        self.models = {}
        self.scalers = {}
    
    def generate_nonlinear_data(self, data_type='moons', n_samples=300, noise=0.3):
        """生成非线性可分数据"""
        if data_type == 'moons':
            X, y = datasets.make_moons(n_samples=n_samples, noise=noise, random_state=42)
        elif data_type == 'circles':
            X, y = datasets.make_circles(n_samples=n_samples, noise=noise, 
                                         factor=0.3, random_state=42)
        else:
            raise ValueError("data_type必须是'moons'或'circles'")
        return X, y
    
    def train_and_visualize(self, X, y, kernels=None, C=1.0):
        """训练并可视化不同核函数的SVM"""
        if kernels is None:
            kernels = ['linear', 'poly', 'rbf', 'sigmoid']
        
        fig, axes = plt.subplots(2, 2, figsize=(15, 12))
        axes = axes.ravel()
        
        for idx, kernel in enumerate(kernels):
            svm = SVC(kernel=kernel, C=C, gamma='scale', random_state=42)
            svm.fit(X, y)
            
            self._plot_boundary(X, y, svm, 
                               f'{kernel.upper()} (Acc: {svm.score(X, y):.3f})',
                               axes[idx])
        
        plt.tight_layout()
        return fig
    
    def _plot_boundary(self, X, y, model, title, ax):
        """绘制决策边界辅助函数"""
        h = 0.02
        x_min, x_max = X[:, 0].min() - 0.5, X[:, 0].max() + 0.5
        y_min, y_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5
        xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                             np.arange(y_min, y_max, h))
        
        Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)
        ax.contourf(xx, yy, Z, alpha=0.4, cmap=plt.cm.RdYlBu)
        
        if hasattr(model, 'decision_function'):
            Z_contour = model.decision_function(np.c_[xx.ravel(), yy.ravel()])
            Z_contour = Z_contour.reshape(xx.shape)
            ax.contour(xx, yy, Z_contour, levels=[-1, 0, 1], 
                      colors='k', linestyles=['--', '-', '--'])
        
        ax.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.RdYlBu, edgecolors='k')
        ax.scatter(model.support_vectors_[:, 0], model.support_vectors_[:, 1],
                  s=200, facecolors='none', edgecolors='k', linewidths=1.5)
        ax.set_title(title)
    
    def hyperparameter_tuning(self, X, y):
        """超参数调优"""
        X_train, X_test, y_train, y_test = train_test_split(
            X, y, test_size=0.2, random_state=42, stratify=y
        )
        
        scaler = StandardScaler()
        X_train_s = scaler.fit_transform(X_train)
        X_test_s = scaler.transform(X_test)
        
        param_grid = {
            'C': [0.1, 1, 10, 100],
            'gamma': ['scale', 'auto', 0.001, 0.01, 0.1, 1],
            'kernel': ['rbf', 'poly']
        }
        
        grid = GridSearchCV(SVC(random_state=42), param_grid, cv=5, n_jobs=-1)
        grid.fit(X_train_s, y_train)
        
        accuracy = grid.score(X_test_s, y_test)
        return grid.best_estimator_, grid.best_params_, accuracy

# 主程序
if __name__ == "__main__":
    guide = SVMPracticalGuide()
    
    # 1. 生成并可视化非线性数据
    print("=" * 50)
    print("步骤1: 生成非线性数据")
    X, y = guide.generate_nonlinear_data('moons', n_samples=300, noise=0.3)
    print(f"数据形状: {X.shape}, 类别分布: {np.bincount(y)}")
    
    # 2. 不同核函数对比
    print("\n" + "=" * 50)
    print("步骤2: 不同核函数效果对比")
    fig = guide.train_and_visualize(X, y)
    plt.savefig('svm_kernel_comparison.png', dpi=150)
    print("对比图已保存为 svm_kernel_comparison.png")
    
    # 3. 超参数调优
    print("\n" + "=" * 50)
    print("步骤3: 超参数调优")
    best_model, best_params, acc = guide.hyperparameter_tuning(X, y)
    print(f"最优参数: {best_params}")
    print(f"测试准确率: {acc:.4f}")
    
    print("\n" + "=" * 50)
    print("所有步骤完成!")

8. 避坑小贴士

8.1 数据预处理的重要性

问题:SVM对特征的尺度敏感,不同量纲的特征会影响核函数的计算。

解决方案

from sklearn.preprocessing import StandardScaler

# 务必进行特征标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)  # 注意:使用训练集的参数

8.2 核函数选择误区

常见错误

  1. 盲目使用RBF核:对于高维稀疏数据(如文本),线性核往往效果更好
  2. 忽略gamma参数:gamma过大导致过拟合,过小导致欠拟合
  3. 多项式核阶数过高:高阶多项式容易导致数值不稳定

建议流程

  1. 先尝试线性核(特别是高维数据)
  2. 如果线性核效果不佳,尝试RBF核
  3. 使用交叉验证调优C和gamma参数

8.3 样本不平衡问题

问题:当两类样本数量差异很大时,SVM会偏向多数类。

解决方案

# 使用class_weight参数
svm = SVC(class_weight='balanced')  # 自动根据类别频率调整权重

# 或手动指定权重
svm = SVC(class_weight={0: 1, 1: 10})  # 类别1的权重是类别0的10倍

8.4 大规模数据的处理

问题:SVM的时间复杂度为 O(n2)O(n^2)O(n2)O(n3)O(n^3)O(n3),不适合大规模数据集。

解决方案

策略适用场景
使用LinearSVC线性核、大规模数据
随机采样数据冗余度高
使用SGDClassifier在线学习场景
分层采样保持类别分布
from sklearn.svm import LinearSVC
from sklearn.linear_model import SGDClassifier

# 大规模数据使用LinearSVC
linear_svm = LinearSVC(C=1.0, max_iter=10000)

# 或使用SGD
sgd_svm = SGDClassifier(loss='hinge', alpha=0.01)  # hinge损失对应SVM

8.5 概率估计的注意事项

问题:SVM本身不输出概率,使用probability=True会进行额外的Platt缩放,增加训练时间。

建议

  • 如果只需要类别预测,不要启用概率估计
  • 如果需要概率,考虑使用CalibratedClassifierCV
# 需要概率时
svm = SVC(probability=True)  # 训练时间会显著增加

# 更好的做法
from sklearn.calibration import CalibratedClassifierCV

svm = SVC()
calibrated = CalibratedClassifierCV(svm, method='sigmoid', cv=5)
calibrated.fit(X_train, y_train)
probs = calibrated.predict_proba(X_test)

8.6 内存优化技巧

问题:核矩阵需要 O(n2)O(n^2)O(n2) 内存,大数据集会内存溢出。

解决方案

# 使用稀疏矩阵(如果适用)
from scipy.sparse import csr_matrix

# 使用内存映射
from sklearn.svm import SVC
import numpy as np

# 分批处理
batch_size = 1000
for i in range(0, len(X), batch_size):
    batch = X[i:i+batch_size]
    predictions = svm.predict(batch)

9. 本章小结

9.1 核心知识点回顾

本章从理论到实践,全面讲解了支持向量机:

理论基础

  1. 最大间隔原则:SVM通过最大化分类间隔获得最优超平面,支持向量决定了决策边界
  2. 对偶问题:通过拉格朗日乘子法将原始问题转化为对偶问题,便于引入核函数
  3. KKT条件:互补松弛条件揭示了支持向量的本质特征
  4. SMO算法:高效的分解算法,每次优化两个变量,保证收敛

核方法

  1. 核技巧:通过核函数隐式映射到高维空间,避免显式计算
  2. Mercer条件:保证核函数有效性的数学基础
  3. 常用核函数:线性核、多项式核、RBF核各有适用场景

扩展应用

  1. 多分类策略:One-vs-One和One-vs-Rest两种主要方法
  2. 支持向量回归:ε-不敏感损失函数扩展到回归问题

9.2 SVM的优势与局限

优势

  • 理论基础扎实,泛化性能有理论保证
  • 通过核方法处理非线性问题
  • 最终模型仅依赖支持向量,存储高效
  • 在高维数据上表现良好(尤其是特征数大于样本数时)

局限

  • 大规模数据集训练速度慢(O(n2)O(n^2)O(n2)O(n3)O(n^3)O(n3)
  • 核函数和参数选择需要经验
  • 对噪声敏感(特别是重叠数据)
  • 缺失值需要预处理

9.3 学习路径建议

初学者

  1. 先掌握线性SVM的直观理解
  2. 通过可视化工具理解不同核函数的效果
  3. 熟练使用Scikit-learn的SVM接口

进阶学习

  1. 深入理解对偶问题的推导过程
  2. 阅读Platt的SMO算法原始论文
  3. 尝试手动实现简化版SMO算法

前沿方向

  1. SVM与深度学习的结合(如SVM作为神经网络的最后一层)
  2. 在线SVM与增量学习
  3. 多核学习与核函数组合

9.4 关键公式速查

概念公式
决策函数f(x)=sign(∑αiyiK(xi,x)+b)f(x) = \text{sign}(\sum \alpha_i y_i K(x_i, x) + b)f(x)=sign(αiyiK(xi,x)+b)
对偶目标max⁡∑αi−12∑∑αiαjyiyjK(xi,xj)\max \sum \alpha_i - \frac{1}{2}\sum\sum \alpha_i\alpha_j y_i y_j K(x_i, x_j)maxαi21∑∑αiαjyiyjK(xi,xj)
RBF核K(x,z)=exp⁡(−γ∣x−z∣2)K(x, z) = \exp(-\gamma |x - z|^2)K(x,z)=exp(γxz2)
多项式核K(x,z)=(γxTz+r)dK(x, z) = (\gamma x^T z + r)^dK(x,z)=(γxTz+r)d
偏置计算b=yi−∑αjyjK(xj,xi)b = y_i - \sum \alpha_j y_j K(x_j, x_i)b=yiαjyjK(xj,xi)

参考资料

  1. Vapnik V. The Nature of Statistical Learning Theory. Springer, 1995.
  2. Platt J. Sequential Minimal Optimization: A Fast Algorithm for Training Support Vector Machines. Microsoft Research, 1998.
  3. Cortes C, Vapnik V. Support-vector networks. Machine Learning, 1995.
  4. Scikit-learn官方文档: https://scikit-learn.org/stable/modules/svm.html

本章完。如有疑问或建议,欢迎在评论区留言讨论。

更多推荐