支持向量机(SVM)是一种经典的分类算法,其核心在于寻找一个最大间隔的超平面来分隔不同类别的数据点。SVM 的**最大间隔**概念确保了分类器具有较好的泛化能力,而**支持向量**是指那些距离超平面最近的样本点,它们决定了超平面的位置。对于线性不可分的数据,SVM 通过**核函数**(如线性核、多项式核、RBF 核和 Sigmoid 核)将数据映射到高维空间,从而实现线性可分。核函数的引入使得 SVM 在处理非线性数据时具有很强的灵活性。此外,SVM 还引入了**软间隔**来处理噪声和异常值,通过调整参数 C 来控制对误分类的容忍度。读者学习后,能够理解 SVM 的工作原理,掌握如何使用核函数处理非线性问题,并能够利用 scikit-learn 等工具进行 SVM 模型的训练和超参数调优。
支持向量机
支持向量机(Support Vector Machine, SVM)是 1990 年代最火的分类算法。它有个非常漂亮的几何直觉:找一条最"宽"的马路,把两类数据分开。
核心直觉:最大间隔
假设我们要在二维平面上分两类点。很多条直线都能分开它们,但哪条最好?
○ ○ ● ●
○ ○ ○ ● ● ●
○ ○ ● ●
──────────────────────────── ← 候选分界线 1
○ ○ ● ●
○ ●
────────────── ← 候选分界线 2 (更靠中间)
○ ○ ● ●
○ ●
────────────── ← 候选分界线 3 (SVM 选的)
SVM 选的不是"任意分界线",而是到两类最近点距离最大的那条。这就是最大间隔(Maximum Margin)。
那些离分界线最近的样本点叫做支持向量(Support Vector)——它们决定了分界线的位置。其它点爱去哪去哪,不影响结果。
形式化:优化目标
设分界线是 w*x + b = 0。最大间隔等价于最小化 ||w||:
min (1/2) * ||w||^2
subject to: y_i * (w*x_i + b) >= 1, 对所有 i
这就是 SVM 的原始优化问题。用拉格朗日乘子法转化成对偶问题后,只有支持向量的 alpha_i > 0,其它点 alpha_i = 0。
核函数:把低维不可分变高维可分
很多真实数据线性不可分——比如经典的"异或"问题:
● ○
○ ●
2D 平面上一条直线分不开。怎么办?映射到高维!
比如把 (x1, x2) 映射到 (x1, x2, x1^2 + x2^2)。在高维空间里,可能就线性可分了。
但显式计算高维映射代价太大。核函数(Kernel Trick)的妙处是:你不需要真的映射,只需要在低维空间里算一个核函数 K(x_i, x_j) = phi(x_i) * phi(x_j)。
常用核函数:
| 核函数 | 公式 | 擅长 |
|---|---|---|
| 线性核 | K(x_i, x_j) = x_i * x_j | 线性可分,数据量大 |
| 多项式核 | K(x_i, x_j) = (x_i*x_j + c)^d | 低维简单非线性 |
| RBF 核(高斯核) | `K(x_i, x_j) = exp(-gamma * | |
| Sigmoid 核 | K(x_i, x_j) = tanh(kappa * x_i*x_j + c) | 类似神经网络 |
软间隔:处理噪声和 outlier
现实数据没有完全线性可分的。SVM 引入软间隔(Soft Margin),允许一些样本被分错:
y_i * (w*x_i + b) >= 1 - xi_i, xi_i >= 0
并把 sum(xi_i) 加到目标函数里作为惩罚。C 参数控制惩罚力度:
C大:对误分类惩罚重 → 间隔窄,过拟合风险高C小:容忍更多误分类 → 间隔宽,泛化更好
实战 sklearn
from sklearn.svm import SVC
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import classification_report
# 1. 数据
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
# 2. SVM 对特征缩放敏感,必须先标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# 3. RBF 核 SVM
model = SVC(kernel='rbf', C=1.0, gamma='scale', random_state=42)
model.fit(X_train, y_train)
# 4. 评估
y_pred = model.predict(X_test)
print(classification_report(y_test, y_pred, target_names=['恶性', '良性']))
超参数调优
SVM 有两个关键超参数,通常用 GridSearch 一起调:
from sklearn.model_selection import GridSearchCV
param_grid = {
'C': [0.1, 1, 10, 100],
'gamma': [0.001, 0.01, 0.1, 1, 'scale'],
'kernel': ['rbf']
}
grid = GridSearchCV(SVC(), param_grid, cv=5, scoring='f1')
grid.fit(X_train, y_train)
print(f"最佳参数: {grid.best_params_}")
print(f"最佳 F1: {grid.best_score_:.3f}")
SVM 的优缺点
优点:
- 几何直觉漂亮,可解释性中等
- 核函数让它在中小数据集上威力很大
- 对高维数据(文本)效果好
- 泛化能力通常不错
缺点:
- 训练慢:样本量 > 10万 时变得不实用
- 对特征缩放敏感
- 超参数(
C,gamma)多,调起来费劲 - 不直接输出概率(可以用 Platt scaling,但代价高)
小结
- SVM 找最大间隔分界,几何直觉强
- 核函数让它能处理非线性,是 SVM 最有魅力的设计
- RBF 核 + 标准化是默认起点
- 数据规模小到中、特征维度高时,SVM 是首选
练习思考
- 为什么 SVM 对特征缩放很敏感?想想距离计算。
- 用
sklearn.datasets.make_circles生成一个同心圆数据,线性核和 RBF 核分别能分开吗? C和gamma各自控制什么?尝试用make_classification跑一个网格搜索,看参数对边界形状的影响。
章末小测验
检验你对《支持向量机》的掌握程度。
SVM 找的超平面有什么特点?
SVM 的核函数(Kernel)是用来做什么的?