非线性支持向量机(SVM)实战指南:从数学原理到Python实现

1次阅读
没有评论

共计 1965 个字符,预计需要花费 5 分钟才能阅读完成。

image.webp

从线性到非线性的跨越

刚开始学 SVM 时,我以为所有数据都能用一条直线分开。直到遇到这样的数据——在二维平面上,两类点像同心圆一样交错分布(用 make_circles 生成的数据集就是典型例子)。这时候线性 SVM 就束手无策了,因为不存在一条直线能完美划分这两个圆圈。这正是非线性 SVM 要解决的问题:通过核函数把数据映射到高维空间,让它们变得线性可分。

非线性支持向量机 (SVM) 实战指南:从数学原理到 Python 实现

核函数的魔法世界

核函数是 SVM 处理非线性问题的核心武器,常见的三种核函数各有特点:

  1. 多项式核:$K(\mathbf{x}, \mathbf{z}) = (\gamma \mathbf{x}^T \mathbf{z} + r)^d$
  2. 适合有明显阶数特征的数据,比如螺旋线
  3. 参数 d 控制多项式阶数,越高越复杂

  4. RBF 核(高斯核):$K(\mathbf{x}, \mathbf{z}) = \exp(-\gamma ||\mathbf{x} – \mathbf{z}||^2)$

  5. 最常用的核函数,像在数据点周围放置小山峰
  6. gamma参数控制山峰的陡峭程度

  7. Sigmoid 核:$K(\mathbf{x}, \mathbf{z}) = \tanh(\gamma \mathbf{x}^T \mathbf{z} + r)$

  8. 表现类似神经网络激活函数
  9. 实际使用较少,可能产生非正定矩阵

数学背后的故事:对偶问题与 KKT 条件

为什么要把原始问题转化为对偶问题?主要有两个原因:
1. 对偶问题只依赖样本间的内积,方便引入核函数
2. 能自然引出支持向量的概念

拉格朗日函数长这样:
$$L(\mathbf{w},b,\alpha) = \frac{1}{2}||\mathbf{w}||^2 – \sum_{i=1}^n \alpha_i[y_i(\mathbf{w}^T\phi(\mathbf{x}_i)+b)-1]$$

KKT 条件就像是交通警察,确保我们的解不会跑偏。最重要的互补松弛条件告诉我们:只有支持向量对应的 $\alpha_i$ 才不为零。

手把手 Python 实战

先准备我们的实验场地:

from sklearn.datasets import make_circles
import matplotlib.pyplot as plt

X, y = make_circles(n_samples=200, noise=0.1, factor=0.4)
plt.scatter(X[:,0], X[:,1], c=y, cmap=plt.cm.Paired)
plt.show()

然后比较不同核函数的效果:

from sklearn.svm import SVC

# 创建不同核函数的 SVM
models = {"RBF": SVC(kernel='rbf', gamma=2),
    "Polynomial": SVC(kernel='poly', degree=3),
    "Sigmoid": SVC(kernel='sigmoid')
}

# 训练并可视化决策边界
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
for (name, model), ax in zip(models.items(), axes):
    model.fit(X, y)
    # 这里省略可视化代码,实际需要画决策边界
    ax.set_title(name)
plt.show()

性能优化实战技巧

当数据量很大时,这两个技巧能救命:

  1. 核缓存设置

    # 调整内核缓存大小(单位 MB)model = SVC(kernel='rbf', cache_size=500)

  2. Nystroem 近似

    from sklearn.kernel_approximation import Nystroem
    
    nystroem = Nystroem(kernel='rbf', n_components=100)
    X_transformed = nystroem.fit_transform(X)
    # 然后可以用线性 SVM 处理转换后的数据

避坑指南

  1. 样本不平衡问题

    # 给少数类更高的权重
    model = SVC(class_weight={0:1, 1:10})

  2. 网格搜索优化

    from sklearn.model_selection import GridSearchCV
    
    param_grid = {'C': [0.1, 1, 10], 'gamma': [0.01, 0.1, 1]}
    grid = GridSearchCV(SVC(), param_grid, n_jobs=-1, verbose=1)
    grid.fit(X_train, y_train)

思考与延伸

  1. 如果数据不是表格而是图结构,如何设计核函数?比如可以尝试图核(Graph Kernel)
  2. 对比简单的全连接神经网络,在相同数据集上:
  3. SVM 通常需要更少的样本
  4. 但神经网络可能自动学习到更好的特征表示

希望这篇笔记能帮你跨过非线性 SVM 的学习门槛。记住,理解核函数的几何意义比死记公式更重要,而实践中的参数调整往往需要耐心和反复实验。

正文完
 0
评论(没有评论)