一、SVM基本原理
1.1 什么是支持向量机?
支持向量机是一种监督学习算法,主要用于分类和回归分析。其核心思想是找到一个最优超平面,使得不同类别的数据点能够被最大间隔分开。这个"最大间隔"正是SVM得名的原因——算法会寻找那些对分类边界起决定性作用的支持向量。
1.2 核心数学概念
1.2.1 超平面方程
对于二维空间,超平面就是一条直线,其方程可以表示为:
其中:
w 是法向量,决定超平面的方向
b 是偏置项,决定超平面的位置
1.2.2 间隔最大化
SVM的目标是最大化间隔(margin),即两个平行超平面之间的距离:
优化问题转化为:
1.3 核技巧(Kernel Trick)
当数据线性不可分时,SVM使用核函数将数据映射到高维空间,使其在高维空间中变得线性可分。常用的核函数包括:
线性核:
多项式核:
RBF核(高斯核):
1.4 正则化参数C
参数C控制着误分类惩罚与间隔大小之间的权衡:
C值较小:间隔较大,允许更多误分类(欠拟合风险)
C值较大:间隔较小,尽可能减少误分类(过拟合风险)
二、实验环境与数据准备
2.1 实验环境配置
# 所需库的安装命令 pip install numpy scipy matplotlib scikit-learn2.2 数据集介绍
本次实验使用两个经典的SVM训练数据集:
ex6data1.mat:线性可分数据集,适合使用线性核
ex6data2.mat:非线性可分数据集,需要RBF核或多项式核
三、完整代码实现与分析
3.1 数据加载与探索
import scipy.io import numpy as np import matplotlib.pyplot as plt from sklearn.svm import SVC from sklearn.preprocessing import StandardScaler # 加载MATLAB格式的数据文件 data1 = scipy.io.loadmat('ex6data1.mat') data2 = scipy.io.loadmat('ex6data2.mat') # 提取特征和标签 X1 = data1['X'] # 特征矩阵 y1 = data1['y'].ravel() # 标签向量,使用ravel()展平 X2 = data2['X'] y2 = data2['y'].ravel() print(f"数据集1: X={X1.shape}, y={y1.shape}") print(f"数据集2: X={X2.shape}, y={y2.shape}")代码解析:
scipy.io.loadmat():专门用于读取MATLAB的.mat格式文件.ravel():将二维标签数组展平为一维,符合scikit-learn的输入要求数据集形状显示了样本数量和特征维度
3.2 数据可视化函数
def plot_dataset(X, y, title="SVM数据集可视化"): """绘制二分类数据集的可视化图""" plt.figure(figsize=(10, 6)) # 分离正负样本 pos = y == 1 neg = y == 0 # 使用不同标记和颜色绘制两类样本 plt.scatter(X[pos, 0], X[pos, 1], c='blue', marker='o', label='正类 (y=1)', s=80, edgecolors='k') plt.scatter(X[neg, 0], X[neg, 1], c='red', marker='x', label='负类 (y=0)', s=80, linewidths=1.5) plt.title(title, fontsize=14) plt.xlabel('特征1') plt.ylabel('特征2') plt.legend(loc='best') plt.grid(True, alpha=0.3) plt.tight_layout() plt.show()可视化技巧:
颜色编码:蓝色表示正类,红色表示负类
标记区分:圆圈表示正类,叉号表示负类
edgecolors='k':为圆圈添加黑色边框,提高可视性alpha=0.3:设置网格线透明度,避免干扰数据点
3.3 SVM训练与可视化核心函数
def train_and_plot_svm(X, y, C=1.0, kernel='linear', title="SVM决策边界"): """训练SVM并绘制决策边界""" # 数据标准化 scaler = StandardScaler() X_scaled = scaler.fit_transform(X) # 创建并训练SVM模型 svm_model = SVC(C=C, kernel=kernel, gamma='scale', probability=True) svm_model.fit(X_scaled, y) # 计算准确率 accuracy = svm_model.score(X_scaled, y) # 创建网格用于决策边界可视化 x_min, x_max = X_scaled[:, 0].min() - 0.5, X_scaled[:, 0].max() + 0.5 y_min, y_max = X_scaled[:, 1].min() - 0.5, X_scaled[:, 1].max() + 0.5 xx, yy = np.meshgrid(np.linspace(x_min, x_max, 300), np.linspace(y_min, y_max, 300)) # 网格点预测 Z = svm_model.predict(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) # 绘制决策边界 plt.figure(figsize=(10, 8)) # 使用两种颜色填充决策区域 from matplotlib.colors import ListedColormap cmap_light = ListedColormap(['#FFAAAA', '#AAAAFF']) plt.contourf(xx, yy, Z, alpha=0.3, cmap=cmap_light) # 绘制决策边界线 plt.contour(xx, yy, Z, colors='k', linewidths=0.5, alpha=0.5) # 绘制数据点 pos = y == 1 neg = y == 0 plt.scatter(X_scaled[pos, 0], X_scaled[pos, 1], c='blue', marker='o', label='正类 (y=1)', s=80, edgecolors='k') plt.scatter(X_scaled[neg, 0], X_scaled[neg, 1], c='red', marker='x', label='负类 (y=0)', s=80, linewidths=1.5) plt.title(f'{title}\nC={C}, kernel={kernel}, 准确率={accuracy:.3f}', fontsize=14) plt.xlabel('特征1 (标准化后)') plt.ylabel('特征2 (标准化后)') plt.legend() plt.grid(True, alpha=0.3) return svm_model, accuracy关键技术点:
数据标准化:
scaler = StandardScaler() X_scaled = scaler.fit_transform(X)将数据标准化为均值为0,方差为1,确保不同特征具有相同的尺度
- 网格创建:
xx, yy = np.meshgrid(np.linspace(x_min, x_max, 300), np.linspace(y_min, y_max, 300))创建300×300的网格点,用于绘制平滑的决策边界
决策边界绘制:
contourf():填充不同类别的区域contour():绘制决策边界线
3.4 不同C值对比实验
# 对比不同C值的SVM表现 fig, axes = plt.subplots(1, 3, figsize=(15, 5)) C_values = [0.1, 1.0, 10.0] for i, C in enumerate(C_values): ax = axes[i] # 训练模型 svm_model = SVC(C=C, kernel='linear', gamma='scale') scaler = StandardScaler() X_scaled = scaler.fit_transform(X1) svm_model.fit(X_scaled, y1) accuracy = svm_model.score(X_scaled, y1) # 支持向量可视化 support_vectors = svm_model.support_vectors_ ax.scatter(support_vectors[:, 0], support_vectors[:, 1], s=100, facecolors='none', edgecolors='yellow', linewidths=2, label=f'支持向量: {len(support_vectors)}') ax.set_title(f'C={C}, 准确率={accuracy:.3f}') ax.legend(loc='upper right', fontsize=8)C值影响分析:
C=0.1:间隔较大,支持向量较多,模型较简单
C=1.0:平衡间隔和分类精度
C=10.0:间隔较小,尽可能正确分类每个样本
四、实验结果与分析
4.1 数据集可视化结果
运行代码后,我们得到的第一张图是两个数据集的原始分布:
观察发现:
ex6data1:数据近似线性可分,正负样本的分布相对分离
ex6data2:数据呈现复杂的非线性分布,正负样本交错分布
4.2 ex6data1线性SVM结果
实验结果:
准确率:通常达到100%或接近100%
决策边界:一条清晰的直线将两类样本分开
支持向量:位于间隔边界上的样本点较少
理论验证:
由于ex6data1是线性可分数据集,线性核SVM能够找到完美的分离超平面,这验证了SVM在线性可分问题上的有效性。
4.3 ex6data2 RBF核SVM结果
实验结果:
准确率:接近100%
决策边界:呈现复杂的非线性形状
分类效果:成功地将交错分布的两类样本分开
核技巧的威力:
RBF核通过将数据映射到高维空间,使得原本非线性可分的问题变得线性可分,展示了核技巧在SVM中的重要作用。
4.4 不同C值对比结果
C值影响分析表:
| C值 | 准确率 | 支持向量数量 | 间隔大小 | 模型复杂度 |
|---|---|---|---|---|
| 0.1 | ~97% | 较多 | 较大 | 较低 |
| 1.0 | ~100% | 适中 | 适中 | 适中 |
| 10.0 | ~100% | 较少 | 较小 | 较高 |
关键发现:
C值与间隔的关系:C值越小,间隔越大,对误分类的容忍度越高
C值与支持向量:C值越大,支持向量通常越少,决策边界更复杂
过拟合风险:C值过大可能导致过拟合,特别是在噪声数据中
五、SVM总结
5.1 核函数选择策略
线性核适用场景:
特征数量远大于样本数量
数据近似线性可分
需要快速训练和预测
RBF核适用场景:
数据非线性可分
没有明确的领域知识指导核选择
通常作为默认尝试的核函数
多项式核适用场景:
了解数据的内在结构
需要显式控制非线性程度(通过degree参数)
六、总结
6.1 实验收获
通过本次SVM实战实验,我获得了以下重要认识:
SVM的核心优势:通过间隔最大化和核技巧,SVM在小样本、高维度和非线性问题上表现优异
参数的重要性:C值和核函数的选择对模型性能有决定性影响
可视化的重要性:决策边界的可视化有助于理解模型的工作原理和局限性
6.2 SVM的局限性
计算复杂度:训练时间复杂度通常为O(
),不适合超大规模数据集
参数敏感:对核函数和正则化参数的选择较为敏感
概率估计:SVM本身不直接提供概率估计,需要通过额外计算获得
结语
支持向量机作为经典机器学习算法仍然是机器学习工具箱中不可或缺的重要工具。通过本次从理论到实践的完整演练,使我认识到:
实践出真知:单纯看理论不如动手做一遍。当看到SVM决策边界从代码中生成,我真正理解了什么是"间隔最大化"。
可视化是关键:把数据画出来,把决策边界画出来,抽象概念瞬间变直观。看图比看公式更能理解算法本质。
参数需要平衡:C值的选择教会我一个重要道理——机器学习不是追求完美分类,而是在过拟合和欠拟合之间找平衡。
并为我后续的深入学习和应用打下坚实基础。