支持向量机实战:从二分类问题到最优决策边界选择

1次阅读
没有评论

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

image.webp

二分类问题的决策边界选择

在二维特征空间中,我们经常会遇到这样的场景:红点和蓝点分别代表两类数据,需要找到一条线将它们分开。如下图所示:

支持向量机实战:从二分类问题到最优决策边界选择

import matplotlib.pyplot as plt
import numpy as np

# 生成示例数据
np.random.seed(42)
red_points = np.random.randn(20, 2) + [1, 1]
blue_points = np.random.randn(20, 2) + [-1, -1]

plt.scatter(red_points[:, 0], red_points[:, 1], color='red')
plt.scatter(blue_points[:, 0], blue_points[:, 1], color='blue')

# 绘制两条可能的决策边界
plt.plot([-2, 2], [2, -2], 'g--', label='边界 1')
plt.plot([-3, 3], [0, 0], 'y--', label='边界 2')
plt.legend()
plt.show()
  • 边界 1(绿色虚线):虽然能完美区分当前数据点,但距离某些点很近
  • 边界 2(黄色虚线):虽然当前分类完全正确,但与两类数据点的距离都较大

显然,边界 2 的泛化能力会更好,因为它为新的数据点留出了更大的缓冲空间。这正是支持向量机(SVM)的核心思想——寻找最大间隔的超平面。

SVM vs 逻辑回归

对于线性可分数据,逻辑回归和 SVM 都能找到决策边界,但优化目标不同:

  1. 逻辑回归:最小化对数损失函数
    $$ J(\theta) = -\frac{1}{m}\sum_{i=1}^m [y^{(i)}\log(h_\theta(x^{(i)})) + (1-y^{(i)})\log(1-h_\theta(x^{(i)}))] $$

  2. 支持向量机:最大化几何间隔
    $$ \max_{\mathbf{w},b} \frac{1}{|\mathbf{w}|} $$
    约束条件:
    $$ y^{(i)}(\mathbf{w}^T\mathbf{x}^{(i)} + b) \geq 1, \quad \forall i $$

这种间隔最大化的特性使 SVM 对噪声和异常值更具鲁棒性。

实战:scikit-learn 实现

1. 数据预处理

from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

# 标准化特征(SVM 对尺度敏感)scaler = StandardScaler()
X_scaled = scaler.fit_transform(np.vstack([red_points, blue_points]))
y = np.array([1]*20 + [0]*20)  # 1 代表红点,0 代表蓝点

# 划分训练测试集
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.3)

2. 模型训练与比较

from sklearn.svm import SVC
import time

# 线性核
linear_svm = SVC(kernel='linear', C=1.0)
start = time.time()
linear_svm.fit(X_train, y_train)
print(f"线性核训练时间:{time.time()-start:.4f}秒")

# RBF 核
rbf_svm = SVC(kernel='rbf', gamma='scale', C=1.0)
start = time.time()
rbf_svm.fit(X_train, y_train)
print(f"RBF 核训练时间:{time.time()-start:.4f}秒")

3. 决策边界可视化

# 创建网格点
xx, yy = np.meshgrid(np.linspace(-3, 3, 200), np.linspace(-3, 3, 200))
Z = linear_svm.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)

# 绘制决策边界
plt.contourf(xx, yy, Z, alpha=0.3)
plt.scatter(X_train[:, 0], X_train[:, 1], c=y_train)
plt.title('线性 SVM 决策边界')
plt.show()

参数调优指南

C 值的影响

  • C 值较大(如 C =100):严格分类,可能导致过拟合
  • C 值较小(如 C =0.01):允许更多误分类,提高泛化能力

核函数选择

  1. 线性核(kernel=’linear’)
  2. 适合特征数多、样本少的情况
  3. 训练速度快

  4. RBF 核(kernel=’rbf’)

  5. 需要调整 gamma 参数
  6. gamma 过大容易过拟合
# 交叉验证寻找最佳 C 值
from sklearn.model_selection import GridSearchCV

param_grid = {'C': [0.01, 0.1, 1, 10, 100]}
grid = GridSearchCV(SVC(kernel='linear'), param_grid, cv=5)
grid.fit(X_train, y_train)
print(f"最佳 C 值:{grid.best_params_}")

常见陷阱与解决方案

  1. 类别不平衡问题

    # 设置 class_weight 参数
    svm_balanced = SVC(kernel='linear', class_weight='balanced')

  2. 大数据集内存问题

  3. 使用 LinearSVC 替代SVC(对线性核更高效)
  4. 对于非线性问题,考虑随机采样或 mini-batch

  5. 高维特征处理

  6. 先用 PCA 降维
  7. 使用线性核减少计算量

扩展思考

当数据中存在噪声点时,我们可以:
1. 适当减小 C 值,允许一些误分类
2. 使用 RBF 核但降低 gamma 值
3. 尝试带权重的 SVM(class_weight

对于超大规模数据,推荐使用 sklearn.linear_model.SGDClassifier 实现线性 SVM,它支持增量式学习。

from sklearn.linear_model import SGDClassifier

sgd_svm = SGDClassifier(loss='hinge', alpha=1/(len(X_train)*1.0))
sgd_svm.fit(X_train, y_train)

通过这次实践,我们对 SVM 的核心思想——最大化间隔有了更直观的理解。记住:好的模型不仅要拟合训练数据,更要为未知数据留出缓冲空间。

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