共计 2671 个字符,预计需要花费 7 分钟才能阅读完成。
二分类问题的决策边界选择
在二维特征空间中,我们经常会遇到这样的场景:红点和蓝点分别代表两类数据,需要找到一条线将它们分开。如下图所示:

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 都能找到决策边界,但优化目标不同:
-
逻辑回归:最小化对数损失函数
$$ 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)}))] $$ -
支持向量机:最大化几何间隔
$$ \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):允许更多误分类,提高泛化能力
核函数选择
- 线性核(kernel=’linear’)
- 适合特征数多、样本少的情况
-
训练速度快
-
RBF 核(kernel=’rbf’)
- 需要调整 gamma 参数
- 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_}")
常见陷阱与解决方案
-
类别不平衡问题
# 设置 class_weight 参数 svm_balanced = SVC(kernel='linear', class_weight='balanced') -
大数据集内存问题
- 使用
LinearSVC替代SVC(对线性核更高效) -
对于非线性问题,考虑随机采样或 mini-batch
-
高维特征处理
- 先用 PCA 降维
- 使用线性核减少计算量
扩展思考
当数据中存在噪声点时,我们可以:
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 的核心思想——最大化间隔有了更直观的理解。记住:好的模型不仅要拟合训练数据,更要为未知数据留出缓冲空间。
