从逻辑回归到 SVM:不仅仅是“分开“

逻辑回归的局限

逻辑回归找到的决策边界是任意一条能将数据分开的直线。问题是:这样的直线有无穷多条。

复制代码
逻辑回归的可能决策边界:

  特征₂
    │                   所有虚线都能把 ○ 和 × 分开
    │  ○ ○ ○             但哪条最好?
    │    ○   ╱ ╲
    │  ○  ╱     ╲ ×
    │   ╱       × ×
    │ ╱     × ×
    └──────────────────→ 特征₁

如果换一组训练数据(稍有不同的采样),逻辑回归可能选到完全不同的另一条线。这意味着模型的方差很大

SVM 的核心思想:最大间隔

SVM(Support Vector Machine)引入了一个关键概念:间隔(Margin)

间隔 = 决策边界到最近训练样本的距离。

SVM 的目标不是随便找一条分开的线,而是找到那一条让间隔最大的线

复制代码
SVM 的最大间隔决策边界:

  特征₂
    │
    │  ○ ○ ○
    │    ○   ╲
    │  ○     ╲   × ×
    │  ╱╲     ╲ ×
    │ ╱  ╲     ×
    │╱    ╲   
    └──────────────────→ 特征₁
      ↑   ↑
    支持向量  ← 这些"最危险的"点决定了边界的位置

二、数学表达:从"间隔"到优化问题

决策边界的表示

延续逻辑回归的符号,决策边界仍然是:

复制代码
w·x + b = 0

对于线性可分的二分类问题:
  w·x + b > 0 → 预测为 +1 类
  w·x + b < 0 → 预测为 -1 类

什么是"间隔"?

对于一个样本 xᵢ,它到决策边界的几何距离是:

复制代码
dᵢ = yᵢ × (w·xᵢ + b) / ||w||

其中 yᵢ ∈ {+1, -1} 是类别标签

当预测正确时,yᵢ 和 (w·xᵢ + b) 同号,dᵢ > 0。

间隔 = 所有样本到决策边界的最短距离

复制代码
Margin = min(dᵢ) 对所有样本 i

SVM 的优化目标

SVM 要找的 w 和 b,就是在正确分类所有样本的前提下,最大化这个最小距离

复制代码
max  Margin(w,b)
s.t. yᵢ × (w·xᵢ + b) / ||w|| ≥ Margin 对所有 i

经过数学变换(令 Margin × ||w|| = 1),可以重写为更简洁的形式:

复制代码
min  (1/2) × ||w||²
s.t. yᵢ × (w·xᵢ + b) ≥ 1  对所有 i

关键 insight:最大化间隔 ⇔ 最小化 ||w||²。

这和岭回归的 L2 正则化在形式上完全一致------SVM 的"最大间隔"本质上等价于在分类任务上做 L2 正则化!


三、支持向量(Support Vectors)

什么是支持向量?

支持向量是那些距离决策边界最近的样本------它们恰好落在间隔边界上:

复制代码
  特征₂
    │
    │  ○ ←─── 这个 ○ 是支持向量
    │    ○ ╲
    │  ○   ╲   × ←─── 这个 × 是支持向量
    │━━━━━━━━━━━━━━━━ 决策边界
    │  ╱     ╲ ×
    │ ╱       × ×
    └──────────────────→ 特征₁

为什么它们叫"支持"向量?

因为这些点是整个模型的"支柱"------只有它们决定了决策边界的位置。其他远离边界的样本,无论怎么移动,只要不越过间隔边界,都不影响决策边界。

支持向量的关键性质

复制代码
# 训练 SVM 后,支持向量的索引
support_vector_indices = model.support_
print(f"支持向量个数: {len(support_vector_indices)}")
# 在 569 个样本中,通常只有 30-80 个是支持向量

# 查看哪些是支持向量
support_vectors = model.support_vectors_
性质 含义
稀疏性 只有少数样本(支持向量)决定模型
鲁棒性 远离边界的样本不影响决策边界
高效性 预测时只需比较新样本和支持向量

这与 KNN 形成鲜明对比------KNN 需要记住所有训练数据,SVM 只需要记住支持向量。


四、软间隔:处理不可分数据

现实世界没有完美线性可分的数据

真实数据通常不是完美线性可分的------总有一些点落在错误的一侧。如果强制要求所有点都分类正确,SVM 可能会找到一个极度扭曲的边界,导致过拟合。

Soft Margin SVM

引入松弛变量(slack variable)ξᵢ,允许一些样本被错误分类或被分到间隔内部:

复制代码
min  (1/2) × ||w||² + C × Σ(ξᵢ)

s.t. yᵢ × (w·xᵢ + b) ≥ 1 - ξᵢ
     ξᵢ ≥ 0

C 是正则化参数,控制"对错误分类的容忍度":

C 值 效果 类比
C 很大(如 100) 间隔窄,几乎不允许错误 严格的老师,训练准确率高,可能过拟合
C 适中(如 1.0) 间隔合理,允许少量错误 正常的老师,泛化能力好
C 很小(如 0.01) 间隔宽,容忍较多错误 宽松的老师,可能欠拟合
复制代码
from sklearn.svm import SVC

# C 越小,正则化越强,决策边界越平滑
svm_strict = SVC(C=100, kernel='linear')      # 严格,边界复杂
svm_normal = SVC(C=1.0, kernel='linear')       # 适中(默认)
svm_loose  = SVC(C=0.01, kernel='linear')      # 宽松,边界平滑

C 的调参:和所有正则化参数一样,用交叉验证选择 C。


五、核技巧(Kernel Trick):SVM 最精妙的设计

线性不可分的问题

很多现实问题不是线性可分的------比如:

复制代码
特征₂                     特征₂
  │                         │
  │    ○ ○                  │      ○      ○
  │   ○   ○                 │    ○   ○  ○   ○
  │  ○     ○                │  ○       ○       ○
  │ ×     ×                 │      ×
  │   ×   ×                 │    ×   ×
  │    × ×                  │  ×       ×
  └──────────→ 特征₁        └──────────────→ 特征₁
  
    线性可分(SVM 直接处理)        线性不可分(需要核技巧)

核心思想:映射到高维空间

对于线性不可分的数据,一个经典思路是:把数据映射到更高维的空间,在高维空间中用线性边界分类。

复制代码
二维空间中线性不可分:
  x₁² + x₂² > r² → 圆内为 +1 类
  无法用一条直线分隔

映射到三维空间:
  令 z = x₁² + x₂²
  在 (x₁, x₂, z) 三维空间中,数据变得线性可分
  → 用一个平面 z = r² 就可以分开

但直接做高维映射的问题:计算量爆炸。如果原始特征是 1000 维,映射到无穷维后根本无法计算。

核函数:隐式完成高维映射

核函数(Kernel Function)的精妙之处在于:不需要显式计算高维空间中的坐标,只需计算两个向量在高维空间中的内积。

复制代码
原始空间中的距离:<xᵢ, xⱼ>  ← 直接计算

高维空间中的内积:K(xᵢ, xⱼ) = <φ(xᵢ), φ(xⱼ)> 
                ← 用核函数一步算出,不需要知道 φ 的具体形式

常用核函数

复制代码
from sklearn.svm import SVC

# 1. 线性核 ------ 等价于不带核的线性 SVM(最快)
svm_linear = SVC(kernel='linear', C=1.0)
# K(x, y) = x · y
# 适用场景:数据本身线性可分,或特征维度很高

# 2. 多项式核 ------ 通过多项式组合特征
svm_poly = SVC(kernel='poly', degree=3, C=1.0)
# K(x, y) = (γ·x·y + coef0)^degree
# 适用场景:有交互特征的数据

# 3. RBF 核(径向基函数)------ 最常用,默认选择
svm_rbf = SVC(kernel='rbf', gamma='scale', C=1.0)
# K(x, y) = exp(-γ × ||x - y||²)
# γ 控制影响半径:γ 越大,每个点的影响范围越小
# 适用场景:大多数非线性问题

# 4. Sigmoid 核
svm_sigmoid = SVC(kernel='sigmoid', gamma='scale', C=1.0)
# K(x, y) = tanh(γ·x·y + coef0)
# 适用场景:类似神经网络的激活函数

核函数对比

核函数 参数 决策边界特点 适用场景 使用频率
线性核 C 直线/平面 高维数据、文本分类 ⭐⭐⭐
RBF 核 C, γ 任意光滑形状 大多数场景,默认首选 ⭐⭐⭐⭐⭐
多项式核 C, degree 多项式曲线 有特征交互 ⭐⭐
Sigmoid 核 C, γ 类似神经网络 特定场景

RBF 核为什么是默认选择?

复制代码
线性核是 RBF 的特例(γ 很小时)
多项式核是 RBF 的近似
→ RBF 覆盖了线性核和多项式核的能力
→ 只有一个额外参数 γ,调参简单

六、SVM 的两个关键参数:C 和 γ

C(正则化参数)

复制代码
C ↑ → 对错误容忍度低 → 边界复杂、可能过拟合
C ↓ → 对错误容忍度高 → 边界平滑、可能欠拟合

调参范围:[0.001, 0.01, 0.1, 1, 10, 100]
默认值:1.0

γ(RBF 核参数)

γ 控制单个样本的影响半径

复制代码
γ ↑ → 每个样本影响范围小 → 决策边界复杂(关注局部细节)
γ ↓ → 每个样本影响范围大 → 决策边界平滑(全局视角)

调参范围:[0.0001, 0.001, 0.01, 0.1, 1, 10]
默认值:'scale' = 1 / (特征数 × X.var())

γ 的直观理解

复制代码
γ = 0.01(小)            γ = 1(适中)              γ = 100(大)

  ┌──────┐                ┌──────┐                ┌──────┐
  │ ╱╲   │                │ ╱╲   │                │╱╲╱╲╱│
  │╱  ╲  │                │╱  ╲  │                │╱╲╱╲╱│
  │    ╲ │                │   ╲  │                │╱╲╱╲╱│
  │     ╲│                │    ╲ │                │╱╲╱╲╱│
  └──────┘                └──────┘                └──────┘
  
  平滑,可能欠拟合       正常,泛化好           复杂,可能过拟合

网格搜索调参

复制代码
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline

# SVM + 标准化(SVM 也是距离算法,必须做特征缩放)
pipeline = make_pipeline(
    StandardScaler(),
    SVC(kernel='rbf')
)

# 参数网格
param_grid = {
    'svc__C': [0.1, 1, 10, 100],
    'svc__gamma': [0.001, 0.01, 0.1, 1, 'scale', 'auto'],
}

# 网格搜索
grid = GridSearchCV(
    pipeline,
    param_grid,
    cv=5,
    scoring='accuracy',
    n_jobs=-1,
    verbose=1
)

grid.fit(X_train, y_train)

print(f"最佳参数: {grid.best_params_}")
print(f"最佳交叉验证准确率: {grid.best_score_:.3f}")
print(f"测试集准确率: {grid.score(X_test, y_test):.3f}")

七、SVM 完整实战:手写数字识别

复制代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
from sklearn.metrics import classification_report, ConfusionMatrixDisplay

# ===== 1. 加载手写数字数据集 =====
# 8×8 像素的手写数字(0-9),1797 个样本
digits = load_digits()
X, y = digits.data, digits.target
print(f"样本数: {X.shape[0]}, 特征数: {X.shape[1]}")
print(f"类别: {digits.target_names}")
# 样本数: 1797, 特征数: 64

# ===== 2. 可视化样本 =====
fig, axes = plt.subplots(2, 5, figsize=(10, 4))
for i, ax in enumerate(axes.ravel()):
    ax.imshow(digits.images[i], cmap='gray')
    ax.set_title(f'数字: {digits.target[i]}')
    ax.axis('off')
plt.tight_layout()
plt.show()

# ===== 3. 划分 =====
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# ===== 4. 构建 SVM 流水线 =====
pipeline = make_pipeline(
    StandardScaler(),
    SVC(kernel='rbf', class_weight='balanced')
)

# ===== 5. 网格搜索调参 =====
param_grid = {
    'svc__C': [0.1, 1, 10, 100],
    'svc__gamma': [0.001, 0.01, 0.1, 'scale'],
}

grid = GridSearchCV(
    pipeline, param_grid, cv=5, scoring='accuracy', n_jobs=-1
)
grid.fit(X_train, y_train)

print(f"最佳参数: {grid.best_params_}")
print(f"最佳交叉验证准确率: {grid.best_score_:.3f}")

# ===== 6. 评估 =====
test_acc = grid.score(X_test, y_test)
y_pred = grid.predict(X_test)

print(f"\n测试集准确率: {test_acc:.3f}")
print("\n分类报告:")
print(classification_report(y_test, y_pred))

# ===== 7. 查看支持向量比例 =====
best_svm = grid.best_estimator_.named_steps['svc']
sv_ratio = len(best_svm.support_vectors_) / len(X_train)
print(f"支持向量: {len(best_svm.support_vectors_)} / {len(X_train)} ({sv_ratio:.1%})")
# 只有约 30-40% 的训练样本是支持向量

输出示例

复制代码
样本数: 1797, 特征数: 64

最佳参数: {'svc__C': 10, 'svc__gamma': 0.01}
最佳交叉验证准确率: 0.985

测试集准确率: 0.989

分类报告:
               precision  recall  f1-score
           0       1.00     1.00     1.00
           1       0.97     1.00     0.99
           2       1.00     1.00     1.00
           3       1.00     0.97     0.99
           4       1.00     0.97     0.99
           5       0.97     0.97     0.97
           6       1.00     1.00     1.00
           7       1.00     1.00     1.00
           8       0.97     0.97     0.97
           9       0.97     1.00     0.99

支持向量: 514 / 1437 (35.8%)

八、SVM vs 逻辑回归 vs KNN

三类算法对比

对比维度 逻辑回归 KNN SVM(RBF 核)
决策边界 线性 非线性(分段) 非线性(核映射)
训练速度 无训练 中等(O(N²~N³))
预测速度 最快 快(仅支持向量)
高维数据 ✅ 好 ❌ 差
可解释性 最好 ❌ 差 ❌ 差
数据量敏感
特征缩放 建议做 必须做 必须做

选型指南

复制代码
特征数 >> 样本数(文本分类 等)
  → 线性 SVM 或 逻辑回归(线性核在特征多时表现好)
  
样本数 >> 特征数(一般结构化数据)
  → RBF 核 SVM 或 随机森林(V 形决策面效果好)
  
数据量大(>10万)
  → 逻辑回归(SVM 训练复杂度 O(N²~N³),大数据太慢)
  
需要可解释性
  → 逻辑回归(能告诉你每个特征的影响)
  
数据低维且小
  → KNN 或 RBF-SVM(都适合小数据)

九、SVR:SVM 做回归

SVM 不仅做分类,也可以做回归------称为 SVR(Support Vector Regression)

SVR 的核心思想与 SVC 相反:

复制代码
SVC(分类):让尽可能多的点在间隔之外(正确分类)
SVR(回归):让尽可能多的点在间隔内部(误差容忍)

┌───────────  ε-不敏感带 ───────────┐
│  预测值 ↑                         │
│          │          ●              │
│          │    ● ●                 │
│          │ ●━━━━━━━━━━━● ●        │
│          │━━━━━━━━━━━━━━━━━━━━    │ ← 预测线
│          │   ● ● ● ● ●━━━━●     │
│          │●              ●         │
│          └────────────────────→ 真实值 │
└─────────────────────────────────────┘
在 ε-不敏感带内的点,误差为 0
带外的点,计算误差

from sklearn.svm import SVR

svr = SVR(kernel='rbf', C=1.0, epsilon=0.1)
# epsilon = ε,控制不敏感带的宽度
svr.fit(X_train, y_train)
y_pred = svr.predict(X_test)

十、SVM 的优缺点与适用场景

优点

  1. 最大间隔 = 内置正则化------泛化能力强
  2. 核技巧------可以用线性模型解决非线性问题
  3. 支持向量稀疏性------只依赖少数关键样本
  4. 高维数据表现好------文本分类等领域表现优异
  5. 理论完备------凸优化保证全局最优解

缺点

  1. 训练复杂度 O(N²~N³)------大数据集上极慢
  2. 没有概率输出------原生 SVM 只输出类别(Platt 缩放可扩展,但增加复杂度)
  3. 参数调优需要经验------C 和 γ 的组合搜索耗时
  4. 不直接支持多分类------需要用 OvR/OvO 策略
  5. 缺乏可解释性------RBF 核的决策边界难以理解

2026 年的 SVM

场景 地位
中小规模数据集 ✅ 仍然是最强算法之一
文本分类 ✅ 线性 SVM 仍是最常用 baseline
大规模数据 ❌ 被 XGBoost 和神经网络取代
图像 ❌ 被深度 CNN/Transformer 彻底取代
需要概率输出 ⚠️ 逻辑回归或神经网络更适合

SVM 的黄金时代(2000-2015 年)已经过去,但在中小规模和文本数据上,它仍然是极有价值的选择。


十一、总结

概念 一句话理解
最大间隔 不只要分开,还要让决策边界离两边越远越好
支持向量 决定边界的"关键少数"------其他的点不重要
软间隔 通过 C 参数允许一些点被分错,防止过拟合
核技巧 不用显式计算高维映射,直接算出高维内积
RBF 核 默认核函数------γ 控制每个点的影响半径

核心三句话

  1. SVM = 线性分类器 + 最大间隔 + 核技巧------三项叠加让它成为经典 ML 的巅峰
  2. 核技巧是高维映射的"物理学"------不实地测量也能算出宇宙的距离
  3. SVM 在小到中等数据上仍是最强选择之一------尤其文本和高维稀疏数据

从线性回归到 SVM,我们走过了经典 ML 中四个最重要的线性/非线性模型。下一篇文章将进入决策树------一个完全不同的世界:不是优化超平面,而是问一系列"是/否"问题。

相关推荐
硅谷秋水1 小时前
ProDrive:基于自身-环境协同演化的自动驾驶主动规划
人工智能·深度学习·机器学习·计算机视觉·自动驾驶
papership1 小时前
【入门级-算法-8、图论算法:泛洪算法 (Flood Fill)】
算法·图论
MartinYeung51 小时前
[论文学习]LLM 情境学习资料的快速精确遗忘技术:基于 In-Context Learning 与量化 K-Means 的 ERASE 方法
学习·算法·kmeans
DXM05212 小时前
第11期| 遥感图像分类模型:ResNet_DenseNet原理+实战训练
人工智能·python·深度学习·机器学习·分类·数据挖掘·ageo
SilentSamsara2 小时前
模型部署实战:FastAPI + ONNX + Docker 的推理服务化
人工智能·pytorch·python·深度学习·机器学习·fastapi
林森lsjs2 小时前
【日耕一题】5. 青春常数(17届蓝桥杯C++B组第一题)
算法·蓝桥杯
Tisfy2 小时前
LeetCode 3838.带权单词映射:求和、取模、拼接(附python一行版)
python·算法·leetcode·字符串·题解·模拟·取模
め.2 小时前
GJK算法实现细节
算法
AI科技星2 小时前
第六卷:量天尺传奇(几何学)
网络·人工智能·算法·概率论·学习方法·几何学·拓扑学