SVM实战:从数学推导到Python代码实现(附完整示例)

发布时间:2026/5/17 20:57:46

SVM实战:从数学推导到Python代码实现(附完整示例) SVM实战从数学推导到Python代码实现附完整示例1. 理解SVM的核心思想支持向量机Support Vector Machine本质上是一种二分类模型它的核心思想可以用一个简单的比喻来理解想象你在操场上需要画一条线将男生和女生分开这条线不仅要能正确分类还要尽可能远离两边的人群。SVM就是在寻找这条最宽容的边界线。从数学角度看SVM要解决的是一个凸优化问题目标最大化分类间隔约束所有样本点都被正确分类这个优化问题可以表示为min 1/2 ||w||² s.t. y_i(w·x_i b) ≥ 1, ∀i其中w是法向量决定了超平面的方向b是位移项决定了超平面与原点的距离。这个看似简单的公式背后蕴含着精妙的数学原理。2. 从理论到代码的关键步骤2.1 构建拉格朗日函数为了求解这个约束优化问题我们需要引入拉格朗日乘子法。构造的拉格朗日函数为def lagrangian(w, b, alpha, X, y): term 0 for i in range(len(alpha)): term alpha[i] * (y[i]*(np.dot(w, X[i]) b) - 1) return 0.5 * np.dot(w, w) - term这个函数将原始约束优化问题转化为无约束优化问题。其中α_i是拉格朗日乘子对应每个样本点。2.2 求解对偶问题通过KKT条件我们可以将原始问题转化为其对偶问题def solve_dual(X, y): n_samples X.shape[0] K np.zeros((n_samples, n_samples)) for i in range(n_samples): for j in range(n_samples): K[i,j] np.dot(X[i], X[j]) P cvxopt.matrix(np.outer(y,y) * K) q cvxopt.matrix(-np.ones(n_samples)) G cvxopt.matrix(np.diag(np.ones(n_samples) * -1)) h cvxopt.matrix(np.zeros(n_samples)) A cvxopt.matrix(y, (1,n_samples)) b cvxopt.matrix(0.0) solution cvxopt.solvers.qp(P, q, G, h, A, b) return np.ravel(solution[x])这个对偶问题的解给出了支持向量α_i 0的样本点它们决定了最终的分类超平面。2.3 计算超平面参数得到α后我们可以计算w和bdef compute_weights(alpha, X, y): w np.zeros(X.shape[1]) for i in range(len(alpha)): w alpha[i] * y[i] * X[i] return w def compute_bias(w, X, y, alpha): support_vector_indices alpha 1e-5 support_vectors X[support_vector_indices] support_vector_labels y[support_vector_indices] b 0 for i in range(len(support_vectors)): b support_vector_labels[i] - np.dot(w, support_vectors[i]) return b / len(support_vectors)3. 完整Python实现下面是一个完整的线性SVM实现使用鸢尾花数据集作为示例import numpy as np import cvxopt from sklearn import datasets from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler class SVM: def __init__(self, kernellinear, C1.0): self.kernel kernel self.C C self.alpha None self.w None self.b None def fit(self, X, y): n_samples, n_features X.shape # 计算核矩阵 K np.zeros((n_samples, n_samples)) for i in range(n_samples): for j in range(n_samples): K[i,j] np.dot(X[i], X[j]) # 构建QP问题 P cvxopt.matrix(np.outer(y,y) * K) q cvxopt.matrix(-np.ones(n_samples)) G cvxopt.matrix(np.vstack((np.diag(-np.ones(n_samples)), np.identity(n_samples)))) h cvxopt.matrix(np.hstack((np.zeros(n_samples), np.ones(n_samples) * self.C))) A cvxopt.matrix(y, (1,n_samples), d) b cvxopt.matrix(0.0) # 求解QP问题 solution cvxopt.solvers.qp(P, q, G, h, A, b) self.alpha np.ravel(solution[x]) # 计算权重 self.w np.zeros(n_features) for i in range(n_samples): self.w self.alpha[i] * y[i] * X[i] # 计算偏置 self.b 0 n_support 0 for i in range(n_samples): if self.alpha[i] 1e-5: self.b y[i] - np.dot(self.w, X[i]) n_support 1 self.b / n_support def predict(self, X): return np.sign(np.dot(X, self.w) self.b) # 加载并预处理数据 iris datasets.load_iris() X iris.data[:, :2] # 只使用前两个特征 y iris.target y np.where(y 0, -1, 1) # 二分类问题 # 数据标准化 scaler StandardScaler() X scaler.fit_transform(X) # 划分训练测试集 X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42) # 训练SVM模型 svm SVM() svm.fit(X_train, y_train) # 评估模型 y_pred svm.predict(X_test) accuracy np.mean(y_pred y_test) print(f测试集准确率: {accuracy:.2f})4. 实战技巧与优化建议4.1 核技巧的应用对于非线性可分数据我们可以引入核函数。以下是常见核函数的实现def linear_kernel(x1, x2): return np.dot(x1, x2) def polynomial_kernel(x1, x2, p3): return (1 np.dot(x1, x2)) ** p def rbf_kernel(x1, x2, gamma0.1): return np.exp(-gamma * np.linalg.norm(x1-x2)**2)在SVM类中添加核函数支持def __init__(self, kernelrbf, C1.0, gamma0.1, degree3): self.kernel kernel self.C C self.gamma gamma self.degree degree # ...其余初始化代码... def fit(self, X, y): n_samples X.shape[0] K np.zeros((n_samples, n_samples)) for i in range(n_samples): for j in range(n_samples): if self.kernel linear: K[i,j] linear_kernel(X[i], X[j]) elif self.kernel poly: K[i,j] polynomial_kernel(X[i], X[j], self.degree) elif self.kernel rbf: K[i,j] rbf_kernel(X[i], X[j], self.gamma) # ...其余拟合代码...4.2 参数调优指南SVM性能很大程度上取决于参数选择参数影响推荐调优范围C惩罚系数控制间隔宽度与分类错误的权衡10^-3 到 10^3 (对数尺度)gamma (RBF核)控制单个样本的影响范围10^-3 到 10^3 (对数尺度)degree (多项式核)多项式次数2 到 5使用网格搜索进行参数优化from sklearn.model_selection import GridSearchCV param_grid { C: [0.1, 1, 10, 100], gamma: [0.1, 0.01, 0.001], kernel: [rbf, linear, poly] } grid GridSearchCV(SVM(), param_grid, refitTrue) grid.fit(X_train, y_train) print(f最佳参数: {grid.best_params_})4.3 处理不平衡数据当类别不平衡时可以给不同类别分配不同的惩罚权重def fit(self, X, y): # 计算类别权重 n_pos np.sum(y 1) n_neg np.sum(y -1) class_weight {1: n_neg/(n_posn_neg), -1: n_pos/(n_posn_neg)} # 修改QP问题的h向量 h_pos np.ones(n_samples) * self.C * class_weight[1] h_neg np.ones(n_samples) * self.C * class_weight[-1] h cvxopt.matrix(np.hstack((np.zeros(n_samples), np.where(y 1, h_pos, h_neg)))) # ...其余拟合代码...5. 可视化与结果分析理解SVM决策边界的最佳方式是通过可视化import matplotlib.pyplot as plt def plot_decision_boundary(model, X, y): # 创建网格 x_min, x_max X[:, 0].min() - 1, X[:, 0].max() 1 y_min, y_max X[:, 1].min() - 1, X[:, 1].max() 1 xx, yy np.meshgrid(np.arange(x_min, x_max, 0.02), np.arange(y_min, y_max, 0.02)) # 预测每个网格点 Z model.predict(np.c_[xx.ravel(), yy.ravel()]) Z Z.reshape(xx.shape) # 绘制结果 plt.contourf(xx, yy, Z, alpha0.4) plt.scatter(X[:, 0], X[:, 1], cy, alpha0.8) plt.xlabel(Feature 1) plt.ylabel(Feature 2) plt.title(SVM Decision Boundary) # 标记支持向量 if hasattr(model, alpha): sv_indices model.alpha 1e-5 plt.scatter(X[sv_indices, 0], X[sv_indices, 1], facecolorsnone, edgecolorsk, s100) plt.show() # 可视化训练结果 plot_decision_boundary(svm, X_train, y_train)可视化结果可以帮助我们直观理解决策边界的位置和形状支持向量的分布分类错误的样本点6. 性能优化技巧6.1 使用缓存加速核计算对于大规模数据核矩阵计算可能很耗时。可以引入缓存机制from functools import lru_cache lru_cache(maxsize1000) def cached_kernel(x1_idx, x2_idx): x1 X_train[x1_idx] x2 X_train[x2_idx] return rbf_kernel(x1, x2, self.gamma)6.2 增量学习对于超大规模数据可以考虑分批训练def partial_fit(self, X_batch, y_batch): if not hasattr(self, alpha): self.alpha np.zeros(X_batch.shape[0]) # 更新核矩阵 K self._compute_kernel(X_batch) # 求解子问题 # ...类似完整fit方法的实现... # 合并结果 self.w ... # 更新权重 self.b ... # 更新偏置6.3 使用稀疏矩阵当特征维度很高时可以使用稀疏矩阵表示from scipy.sparse import csr_matrix def fit(self, X, y): if isinstance(X, np.ndarray): X csr_matrix(X) # 其余实现保持不变...7. 常见问题解决方案7.1 处理收敛问题当QP问题不收敛时可以尝试增加最大迭代次数cvxopt.solvers.options[maxiters] 500调整收敛容差cvxopt.solvers.options[abstol] 1e-6 cvxopt.solvers.options[reltol] 1e-57.2 内存优化对于大数据集核矩阵可能占用过多内存。解决方案使用近似方法如Nystroem近似采用线性核不需要存储核矩阵使用核缓存策略7.3 多分类扩展SVM本质上是二分类器。多分类问题的常见解决方案一对多One-vs-Rest一对一One-vs-One使用多类SVM扩展实现一对多策略示例class MultiClassSVM: def __init__(self, n_classes): self.classifiers [SVM() for _ in range(n_classes)] def fit(self, X, y): for i, clf in enumerate(self.classifiers): # 创建二分类标签 y_binary np.where(y i, 1, -1) clf.fit(X, y_binary) def predict(self, X): decisions np.zeros((X.shape[0], len(self.classifiers))) for i, clf in enumerate(self.classifiers): decisions[:, i] np.dot(X, clf.w) clf.b return np.argmax(decisions, axis1)

相关新闻