共计 2049 个字符,预计需要花费 6 分钟才能阅读完成。
支持向量机 (SVM) 凭借其出色的泛化能力,在文本分类和生物特征识别等领域表现优异,尤其适合小样本、高维度的复杂分类场景。本文将手把手带您实现一个完整 SVM 分类器,并深入探讨调参技巧与性能优化。

一、理解 SVM 的核心数学原理
硬间隔SVM 的原始优化目标为:
$$\min_{w,b} \frac{1}{2}||w||^2 \quad s.t. \quad y_i(w^Tx_i + b) \geq 1$$
当数据线性不可分时,引入 软间隔 的松弛变量 $\xi$:
$$\min_{w,b} \frac{1}{2}||w||^2 + C\sum_{i=1}^n \xi_i \quad s.t. \quad y_i(w^Tx_i + b) \geq 1-\xi_i$$
- 核函数选择策略:
- RBF 核:$K(x_i,x_j)=exp(-\gamma||x_i-x_j||^2)$,适合处理局部特征明显的非线性数据
- 多项式核:$K(x_i,x_j)=(\gamma x_i^Tx_j + r)^d$,适用于全局特征关系
二、从零实现 SVM 分类器
以下代码演示基于 QP 求解器的完整实现流程(使用 cvxopt 库):
import numpy as np
from cvxopt import matrix, solvers
# 数据标准化函数
def standardize(X):
return (X - np.mean(X, axis=0)) / np.std(X, axis=0)
class SVM:
def __init__(self, kernel='rbf', C=1.0, gamma=0.1):
self.kernel = kernel
self.C = C # 惩罚系数
self.gamma = gamma # 核函数参数
def fit(self, X, y):
n_samples, n_features = X.shape
# 构建 QP 问题的矩阵参数
K = self._kernel_matrix(X)
P = matrix(np.outer(y,y) * K)
q = matrix(-np.ones(n_samples))
# 约束条件:0 ≤ α_i ≤ C 且 ∑α_i y_i = 0
G = matrix(np.vstack((-np.eye(n_samples), np.eye(n_samples))))
h = matrix(np.hstack((np.zeros(n_samples), np.ones(n_samples) * self.C)))
A = matrix(y.reshape(1, -1).astype(float))
b = matrix(0.0)
# 调用 QP 求解器
solution = solvers.qp(P, q, G, h, A, b)
alpha = np.ravel(solution['x'])
# 提取支持向量(α_i > 0 的样本)
sv = alpha > 1e-5
self.alpha = alpha[sv]
self.sv_X = X[sv]
self.sv_y = y[sv]
# 计算截距 b
self.b = np.mean(
[y_k - np.sum(self.alpha * self.sv_y *
self._kernel_func(self.sv_X, x_k.reshape(1,-1)))
for x_k, y_k in zip(self.sv_X, self.sv_y)])
def _kernel_func(self, x1, x2):
if self.kernel == 'rbf':
return np.exp(-self.gamma * np.sum((x1 - x2)**2, axis=1))
elif self.kernel == 'poly':
return (self.gamma * np.dot(x1, x2.T) + 1)**2
def predict(self, X):
return np.sign(np.sum(
self.alpha * self.sv_y *
self._kernel_func(self.sv_X, X), axis=0) + self.b)
三、性能优化关键技巧
- 时间复杂度控制:
- 传统 SVM 的 QP 求解复杂度约为 $O(n^3)$
-
对于大规模数据,可采用随机梯度下降 (SGD) 或使用 LIBSVM 的缓存优化策略
-
内存优化方案:
- 使用稀疏矩阵存储核矩阵
- 对 RBF 核采用 Nyström 方法低秩近似
四、实战中的避坑指南
-
特征缩放必要性:
RBF 核依赖样本间距离计算,必须对特征做标准化处理,否则大数值特征会主导核函数输出 -
类别不平衡处理:
调整 class_weight 参数,对少数类赋予更高惩罚系数:# 计算类别权重 class_weights = {1: len(y)/(2*np.sum(y==1)), -1: len(y)/(2*np.sum(y==-1))}
五、开放性问题探讨
- 如何改进 QP 求解器使其能处理百万级样本?
- 当特征维度远大于样本量时,哪些核函数更有效?
- 如何设计增量学习机制使 SVM 支持在线更新?
通过本次实践,我们不仅实现了 SVM 的核心算法,更重要的是理解了其背后的设计哲学——在模型复杂度与泛化能力之间寻找最优平衡点。建议读者尝试在 UCI 数据集上验证本实现,并思考不同核函数在具体业务场景中的选择逻辑。
正文完
发表至: 未分类
近三天内
