【机器学习精通】第7章 | 支持向量机与核方法:理论推导与核技巧
摘要:本章深入讲解支持向量机(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
学习目标
完成本章学习后,你将能够:
- 理解最大间隔分类的直观原理与支持向量的核心作用
- 独立完成SVM原始问题到对偶问题的完整数学推导
- 掌握KKT条件在SVM中的应用与几何解释
- 理解SMO算法的启发式选择策略与收敛性分析
- 深入理解核技巧的数学本质与Mercer条件
- 熟练运用Scikit-learn实现多分类SVM与支持向量回归
- 独立完成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}^nw∈Rn 是法向量,决定超平面的方向
- b∈Rb \in \mathbb{R}b∈R 是偏置项,决定超平面到原点的距离
函数间隔与几何间隔:
对于样本点 (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=∣w∣yi(wTxi+b) | 具有尺度不变性 |
几何意义:
几何间隔表示样本点到超平面的实际欧氏距离。对于分类正确的样本,几何间隔为正;分类错误则为负。
1.3 支持向量的概念
定义:支持向量是距离分离超平面最近的样本点,它们"支撑"着最大间隔边界。
关键性质:
- 支持向量位于间隔边界上,满足 yi(wTxi+b)=1y_i(w^T x_i + b) = 1yi(wTxi+b)=1
- 最终决策函数仅依赖于支持向量:f(x)=∑i∈SVαiyixiTx+bf(x) = \sum_{i \in SV} \alpha_i y_i x_i^T x + bf(x)=∑i∈SVαiyixiTx+b
- 非支持向量的系数 αi=0\alpha_i = 0αi=0,对模型无贡献
直观比喻:
想象在两类样本之间放置一块木板(超平面),支持向量就是那些"顶住"木板边缘的样本点。移动其他样本点(只要不超过间隔边界)不会改变木板的位置。
1.4 线性可分与软间隔
线性可分情况:
当存在一个超平面能完美分离两类样本时,我们称之为线性可分。此时可以求解"硬间隔"SVM。
线性不可分情况:
现实数据往往存在噪声或重叠,此时引入"软间隔":
- 允许部分样本分类错误
- 引入松弛变量 ξi≥0\xi_i \geq 0ξi≥0 度量违规程度
- 在目标函数中添加惩罚项 C∑i=1nξiC \sum_{i=1}^n \xi_iC∑i=1nξi
参数 CCC 控制间隔宽度与分类错误的权衡:
- CCC 较大:强调正确分类,间隔较窄,可能过拟合
- CCC 较小:允许更多错误,间隔较宽,可能欠拟合
2. SVM原始问题与对偶问题推导
2.1 原始优化问题
硬间隔SVM的原始问题:
minw,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.21∥w∥2yi(wTxi+b)≥1,i=1,2,...,n
目标函数的几何解释:
最小化 12∥w∥2\frac{1}{2}\|w\|^221∥w∥2 等价于最大化几何间隔 1∥w∥\frac{1}{\|w\|}∥w∥1。系数 12\frac{1}{2}21 是为了求导方便。
软间隔SVM的原始问题:
minw,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.21∥w∥2+Ci=1∑nξiyi(wTxi+b)≥1−ξi,i=1,2,...,nξi≥0,i=1,2,...,n
2.2 拉格朗日函数构建
引入拉格朗日乘子 αi≥0\alpha_i \geq 0αi≥0 和 μi≥0\mu_i \geq 0μi≥0,构建拉格朗日函数:
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,ξ,α,μ)=21∥w∥2+Ci=1∑nξi−i=1∑nαi[yi(wTxi+b)−1+ξi]−i=1∑nμiξi
各项含义:
| 项 | 含义 |
|---|---|
| 12∣w∣2\frac{1}{2}|w|^221∣w∣2 | 最大化间隔的目标 |
| 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 ∂w∂L=w−i=1∑nαiyixi=0⇒w=i=1∑nα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 ∂b∂L=−i=1∑nαiyi=0⇒i=1∑nα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 ∂ξi∂L=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=1∑nj=1∑nαiαjyiyjxiTxj+Ci=1∑nξi−i=1∑nαiyi(j=1∑nαjyjxjT)xi−bi=1∑nαiyi+i=1∑nαi−i=1∑nαiξi−i=1∑nμiξi=−21i=1∑nj=1∑nαiαjyiyjxiTxj+i=1∑nα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=1∑nαi−21i=1∑nj=1∑nαiαjyiyjxiTxji=1∑nαiyi=00≤αi≤C,i=1,2,...,n
2.4 KKT条件分析
KKT条件是原始问题与对偶问题最优解的充要条件:
-
平稳性条件: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 = 0∑i=1nαiyi=0
-
原始可行性: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ξi≥0
-
对偶可行性:αi≥0\alpha_i \geq 0αi≥0,μi≥0\mu_i \geq 0μi≥0
-
互补松弛条件:
- α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=0 | yi(wTxi+b)>1y_i(w^T x_i + b) > 1yi(wTxi+b)>1 | 间隔边界外 | 非支持向量 |
| 0<αi<C0 < \alpha_i < C0<αi<C | yi(wTxi+b)=1y_i(w^T x_i + b) = 1yi(wTxi+b)=1 | 间隔边界上 | 自由支持向量 |
| αi=C\alpha_i = Cαi=C | yi(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=yi−j=1∑nα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=1∑nαi∗yixiTx+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=3∑nαiyi=ζ(常数)
边界约束:
- 若 y1≠y2y_1 \neq y_2y1=y2:max(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)≤α2new≤min(C,C+α2−α1)
- 若 y1=y2y_1 = y_2y1=y2:max(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+α1−C)≤α2new≤min(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)+b−yi
令 η=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(E1−E2)
裁剪到可行域:
α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,unc≤Hif α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 启发式变量选择策略
外层循环:选择第一个变量
- 首先遍历所有样本,寻找违反KKT条件的样本
- 若未找到,遍历整个训练集
- 若仍未找到,算法终止
内层循环:选择第二个变量
目标是使 ∣E1−E2∣|E_1 - E_2|∣E1−E2∣ 最大化,这样更新步长最大。具体策略:
- 若 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=−E1−y1K(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算法保证收敛到全局最优解,因为:
- 每次迭代目标函数值不减
- 目标函数有上界(对偶问题的最优值)
- 算法在有限步内收敛
实际应用中,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=1∑nxizi)2=i=1∑nxi2zi2+i=1∑nj=i+1∑n2xixjzizj
对应特征映射:
ϕ(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,...,2xn−1xn)
特征维度从 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σ2∥x−z∥2)=exp(−γ∥x−z∥2)
其中 γ=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(−γ∥x−z∥2)=exp(−γ∥x∥2)exp(−γ∥z∥2)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=0∑∞k!(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(−γ∣x−z∣2) | γ\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}K∈Rn×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)
性质:
- 对称性:Kij=KjiK_{ij} = K_{ji}Kij=Kji
- 半正定性:对于任意向量 c∈Rnc \in \mathbb{R}^nc∈Rn,cTKc≥0c^T K c \geq 0cTKc≥0
证明半正定性:
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=1∑nj=1∑ncicjK(xi,xj)=i=1∑nj=1∑ncicjϕ(xi)Tϕ(xj)=i=1∑nciϕ(xi)2≥0
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))的充要条件是:
- 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)
- 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)dxdz≥0
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=1∑nαi−21i=1∑nj=1∑nαiαjyiyjK(xi,xj)i=1∑nαiyi=00≤αi≤C
决策函数:
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=1∑nαi∗yiK(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(k−1) 个分类器
- 每个分类器区分一对类别
- 预测时投票,得票最多的类别为最终预测
优点:
- 每个子问题训练样本少,计算效率高
- 适用于类别数较少的情况
缺点:
- 分类器数量随类别数平方增长
- 可能存在投票平局
One-vs-Rest(OvR):
- 对于 kkk 个类别,训练 kkk 个分类器
- 每个分类器将一个类别与所有其他类别区分
- 预测时选择输出值最大的类别
优点:
- 分类器数量线性增长
- 决策边界清晰
缺点:
- 每个分类器面对不平衡数据
- 训练样本量大
策略对比:
| 特性 | One-vs-One | One-vs-Rest |
|---|---|---|
| 分类器数量 | k(k−1)/2k(k-1)/2k(k−1)/2 | kkk |
| 每个分类器训练样本 | 较少 | 全部 |
| 预测速度 | 较慢 | 较快 |
| 适用场景 | 类别数少 | 类别数多 |
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,∣y−f(x)∣−ϵ,if ∣y−f(x)∣≤ϵotherwise
原始优化问题:
minw,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.21∥w∥2+Ci=1∑n(ξi+ξi∗)yi−wTxi−b≤ϵ+ξiwTxi+b−yi≤ϵ+ξi∗ξi,ξi∗≥0
对偶问题:
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∗)+i∑yi(αi−αi∗)i∑(αi−αi∗)=00≤αi,αi∗≤C
决策函数:
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=1∑n(αi−αi∗)K(xi,x)+b
支持向量的定义:
在SVR中,满足 ∣yi−f(xi)∣≥ϵ|y_i - f(x_i)| \geq \epsilon∣yi−f(xi)∣≥ϵ 的样本是支持向量,它们位于管道的边界之外。
6.3 SVR参数调优
| 参数 | 作用 | 调优建议 |
|---|---|---|
| C | 惩罚系数 | 控制模型复杂度,通过交叉验证选择 |
| ε | 不敏感区域宽度 | 较大值使模型更平滑,较小值更精确 |
| kernel | 核函数类型 | 根据数据特性选择 |
| γ | RBF核参数 | 影响单个样本的影响范围 |
7. 实战案例:SVM可视化与图像分类
7.1 案例概述
本案例包含三个部分:
- 二维数据SVM决策边界可视化
- 不同核函数效果对比
- 手写数字图像分类
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 核函数选择误区
常见错误:
- 盲目使用RBF核:对于高维稀疏数据(如文本),线性核往往效果更好
- 忽略gamma参数:gamma过大导致过拟合,过小导致欠拟合
- 多项式核阶数过高:高阶多项式容易导致数值不稳定
建议流程:
- 先尝试线性核(特别是高维数据)
- 如果线性核效果不佳,尝试RBF核
- 使用交叉验证调优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 核心知识点回顾
本章从理论到实践,全面讲解了支持向量机:
理论基础:
- 最大间隔原则:SVM通过最大化分类间隔获得最优超平面,支持向量决定了决策边界
- 对偶问题:通过拉格朗日乘子法将原始问题转化为对偶问题,便于引入核函数
- KKT条件:互补松弛条件揭示了支持向量的本质特征
- SMO算法:高效的分解算法,每次优化两个变量,保证收敛
核方法:
- 核技巧:通过核函数隐式映射到高维空间,避免显式计算
- Mercer条件:保证核函数有效性的数学基础
- 常用核函数:线性核、多项式核、RBF核各有适用场景
扩展应用:
- 多分类策略:One-vs-One和One-vs-Rest两种主要方法
- 支持向量回归:ε-不敏感损失函数扩展到回归问题
9.2 SVM的优势与局限
优势:
- 理论基础扎实,泛化性能有理论保证
- 通过核方法处理非线性问题
- 最终模型仅依赖支持向量,存储高效
- 在高维数据上表现良好(尤其是特征数大于样本数时)
局限:
- 大规模数据集训练速度慢(O(n2)O(n^2)O(n2)到O(n3)O(n^3)O(n3))
- 核函数和参数选择需要经验
- 对噪声敏感(特别是重叠数据)
- 缺失值需要预处理
9.3 学习路径建议
初学者:
- 先掌握线性SVM的直观理解
- 通过可视化工具理解不同核函数的效果
- 熟练使用Scikit-learn的SVM接口
进阶学习:
- 深入理解对偶问题的推导过程
- 阅读Platt的SMO算法原始论文
- 尝试手动实现简化版SMO算法
前沿方向:
- SVM与深度学习的结合(如SVM作为神经网络的最后一层)
- 在线SVM与增量学习
- 多核学习与核函数组合
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∑αi−21∑∑αiαjyiyjK(xi,xj) |
| RBF核 | K(x,z)=exp(−γ∣x−z∣2)K(x, z) = \exp(-\gamma |x - z|^2)K(x,z)=exp(−γ∣x−z∣2) |
| 多项式核 | 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) |
参考资料:
- Vapnik V. The Nature of Statistical Learning Theory. Springer, 1995.
- Platt J. Sequential Minimal Optimization: A Fast Algorithm for Training Support Vector Machines. Microsoft Research, 1998.
- Cortes C, Vapnik V. Support-vector networks. Machine Learning, 1995.
- Scikit-learn官方文档: https://scikit-learn.org/stable/modules/svm.html
本章完。如有疑问或建议,欢迎在评论区留言讨论。
更多推荐
所有评论(0)