Machine Learning: SVM支持向量机 — 最大间隔与核技巧分类指南

SVM找的是"最宽的马路"——让分类边界离两边数据都尽可能远,自然更稳健。

1. 你将学到


2. 一个市场分析师的真实故事

(1) 痛点:客户价值分层边界模糊

Charlie负责欧洲市场的客户分层,需要将客户分为High/Medium/Low三个价值等级来分配服务资源。但High和Medium的边界很难划——用单一指标(如消费额)分层,边界附近20%的客户频繁被误分。线性边界无法捕捉客户多维度特征的复杂关系。

(2) SVM核技巧的解法

SVM通过核技巧将数据映射到高维空间,在原来不可分的数据中找到清晰边界。

PYTHON
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

# RBF kernel maps to high-dimensional space
pipe = Pipeline([
    ("scaler", StandardScaler()),
    ("svm", SVC(kernel="rbf", C=1.0, gamma="scale")),
])
pipe.fit(X_train, y_train)
print(f"Accuracy: {pipe.score(X_test, y_test):.4f}")

(3) 收益:边界客户分类准确率从65%提升到89%

Charlie用SVM-RBF替代线性分层后,边界附近客户的分类准确率从65%提升到89%,服务资源错配率降低40%。


3. 最大间隔分类器

(1) SVM核心思想

SVM寻找使间隔(margin)最大的分类超平面,只有落在间隔边界上的样本(支持向量)决定分类结果。

100%
graph TB
    INPUT[Input Data] --> MAP[Kernel Mapping<br/>Low-D → High-D]
    MAP --> HYPER[Find Max-Margin<br/>Hyperplane]
    HYPER --> SV[Support Vectors<br/>Define the boundary]
    SV --> MARGIN[Margin Width<br/>Larger = More Robust]
    MARGIN --> CLASSIFY[Classification<br/>Decision Function]

▶ 示例:线性SVM可视化

PYTHON
from sklearn.svm import SVC
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
import numpy as np

X, y = make_blobs(n_samples=100, centers=2, random_state=42, cluster_std=1.5)

# Train SVM with linear kernel
svm = SVC(kernel="linear", C=1.0)
svm.fit(X, y)

fig, ax = plt.subplots(figsize=(8, 6))

# Plot data points
ax.scatter(X[:, 0], X[:, 1], c=y, cmap="bwr", s=30, edgecolors="black")

# Plot decision boundary and margins
xlim = ax.get_xlim()
ylim = ax.get_ylim()
xx = np.linspace(xlim[0], xlim[1], 30)
yy = np.linspace(ylim[0], ylim[1], 30)
YY, XX = np.meshgrid(yy, xx)
xy = np.vstack([XX.ravel(), YY.ravel()]).T
Z = svm.decision_function(xy).reshape(XX.shape)

ax.contour(XX, YY, Z, colors="k", levels=[-1, 0, 1], alpha=0.5, linestyles=["--", "-", "--"])

# Highlight support vectors
ax.scatter(svm.support_vectors_[:, 0], svm.support_vectors_[:, 1],
           s=100, facecolors="none", edgecolors="k", linewidths=2)
ax.set_title(f"Linear SVM (C={svm.C})\nSupport vectors: {len(svm.support_vectors_)}")
plt.tight_layout()
plt.savefig("svm_linear.png", dpi=150)

输出:

TEXT 📖 仅展示
# 执行成功

(2) 硬间隔 vs 软间隔(C参数)

C值 间隔 误分类容忍 过拟合风险 适用场景
很大(100+) 几乎不容忍 数据几乎线性可分
中等(1) 适中 少量容忍 一般情况
很小(0.01) 高容忍 有噪声/重叠

▶ 示例:C参数影响对比

PYTHON
from sklearn.svm import SVC
from sklearn.datasets import make_blobs
from sklearn.model_selection import cross_val_score
import numpy as np

X, y = make_blobs(n_samples=200, centers=2, random_state=42, cluster_std=2.5)

for C in [0.01, 0.1, 1.0, 10.0, 100.0]:
    svm = SVC(kernel="rbf", C=C, gamma="scale")
    scores = cross_val_score(svm, X, y, cv=5, scoring="accuracy")
    svm.fit(X, y)
    print(f"C={C:6.2f}: Accuracy={scores.mean():.3f} +/- {scores.std():.3f}, "
          f"Support vectors={len(svm.support_vectors_)}")

输出:

TEXT 📖 仅展示
# 执行成功

4. 核技巧

(1) 核函数选择

▶ 示例:不同核函数对比

PYTHON
from sklearn.svm import SVC
from sklearn.datasets import make_moons, make_circles
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
import numpy as np

# Non-linear data (moons)
X_moons, y_moons = make_moons(n_samples=500, noise=0.2, random_state=42)

kernels = {
    "Linear": SVC(kernel="linear", C=1),
    "Polynomial (deg=3)": SVC(kernel="poly", degree=3, C=1),
    "RBF": SVC(kernel="rbf", C=1, gamma="scale"),
}

for name, svm in kernels.items():
    pipe = Pipeline([("scaler", StandardScaler()), ("svm", svm)])
    scores = cross_val_score(pipe, X_moons, y_moons, cv=5, scoring="accuracy")
    print(f"{name:20s}: Accuracy={scores.mean():.3f}")

输出:

TEXT 📖 仅展示
# 执行成功
核函数 公式 适用场景 关键参数
Linear $\langle x, x' \rangle$ 高维、线性可分 C
RBF $e^{-\gamma|x-x'|^2}$ 通用,非线性 C, gamma
Polynomial $(\langle x, x' \rangle + c)^d$ 特征交互 C, degree, coef0
Sigmoid $\tanh(\gamma\langle x, x' \rangle + c)$ 类神经网络 C, gamma, coef0

(2) gamma参数

▶ 示例:gamma参数对RBF核的影响

PYTHON
from sklearn.svm import SVC
from sklearn.datasets import make_moons
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

X, y = make_moons(n_samples=500, noise=0.15, random_state=42)

for gamma in [0.01, 0.1, 1.0, 10.0, "scale", "auto"]:
    pipe = Pipeline([
        ("scaler", StandardScaler()),
        ("svm", SVC(kernel="rbf", C=1, gamma=gamma)),
    ])
    scores = cross_val_score(pipe, X, y, cv=5, scoring="accuracy")
    print(f"gamma={str(gamma):6s}: Accuracy={scores.mean():.3f}")

输出:

TEXT 📖 仅展示
# 执行成功
gamma 决策边界 效果
很小(0.01) 平滑 欠拟合
适中(1) 适度弯曲 通常最佳
很大(10+) 极不规则 过拟合
"scale" 1/(n_features * X.var()) sklearn默认
"auto" 1/n_features 旧版默认

5. 标准化必要性与SVR

(1) SVM对特征尺度的敏感性

▶ 示例:标准化对SVM的影响

PYTHON
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris

X, y = load_iris(return_X_y=True)

# Without scaling
svm_raw = SVC(kernel="rbf", C=1, gamma="scale")
scores_raw = cross_val_score(svm_raw, X, y, cv=5, scoring="accuracy")

# With scaling
pipe = Pipeline([("scaler", StandardScaler()), ("svm", SVC(kernel="rbf", C=1, gamma="scale"))])
scores_scaled = cross_val_score(pipe, X, y, cv=5, scoring="accuracy")

print(f"Without scaling: {scores_raw.mean():.4f}")
print(f"With scaling:    {scores_scaled.mean():.4f}")

输出:

TEXT 📖 仅展示
# 执行成功
⚠️ 注意: SVM使用距离度量计算间隔,如果特征尺度差异大(如年龄0-100 vs 收入0-1000000),大尺度特征会主导间隔计算。SVM必须配合StandardScaler。

(2) SVR回归

▶ 示例:SVR销售预测

PYTHON
from sklearn.svm import SVR
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, r2_score
import numpy as np

rng = np.random.default_rng(42)
X = rng.uniform(0, 100, (200, 3))
y = 50 + 0.8 * X[:, 0] + rng.normal(0, 5, 200)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# SVR with RBF kernel
pipe = Pipeline([
    ("scaler", StandardScaler()),
    ("svr", SVR(kernel="rbf", C=100, epsilon=5)),
])
pipe.fit(X_train, y_train)
y_pred = pipe.predict(X_test)

print(f"SVR R²: {r2_score(y_test, y_pred):.4f}")
print(f"SVR MAE: {mean_absolute_error(y_test, y_pred):.2f}")

输出:

TEXT 📖 仅展示
# 执行成功
参数 含义 效果
C 正则化强度 大C→少容忍误差→可能过拟合
epsilon (ε) 不敏感带宽度 大ε→更多点被忽略→更平滑
kernel 核函数类型 同分类SVM

6. Charlie的欧洲客户价值分层

▶ 示例:完整SVM分类项目

PYTHON
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.metrics import classification_report
import pandas as pd
import numpy as np

rng = np.random.default_rng(42)
n = 2000
df = pd.DataFrame({
    "annual_spending_eur": rng.exponential(5000, n),
    "purchase_frequency": rng.poisson(8, n),
    "avg_order_value_eur": rng.exponential(150, n),
    "tenure_months": rng.integers(1, 60, n),
    "support_tickets": rng.poisson(3, n),
})

# Value tier logic (EUR-based)
score = (df["annual_spending_eur"] / 5000 * 0.3
         + df["purchase_frequency"] / 20 * 0.25
         + df["avg_order_value_eur"] / 200 * 0.2
         + df["tenure_months"] / 60 * 0.15
         + rng.normal(0, 0.1, n))

df["tier"] = pd.cut(score, bins=[0, 0.3, 0.6, 1.5], labels=["Low", "Medium", "High"])

X = df.drop(columns=["tier"])
y = df["tier"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)

# Grid search for best SVM parameters
pipe = Pipeline([("scaler", StandardScaler()), ("svm", SVC())])
param_grid = {
    "svm__kernel": ["linear", "rbf"],
    "svm__C": [0.1, 1, 10],
    "svm__gamma": ["scale", 0.1, 1],
}

grid = GridSearchCV(pipe, param_grid, cv=3, scoring="accuracy", n_jobs=-1)
grid.fit(X_train, y_train)

print(f"Best params: {grid.best_params_}")
print(f"Best CV accuracy: {grid.best_score_:.4f}")
print(f"\nTest report:\n{classification_report(y_test, grid.predict(X_test))}")

输出:

TEXT 📖 仅展示
# 执行成功

❓ 常见问题

Q SVM为什么必须标准化?
A SVM基于距离度量计算间隔。如果特征A范围0-1,特征B范围0-1000000,B会完全主导间隔计算。StandardScaler让所有特征贡献均衡。
Q RBF核的gamma和C哪个更重要?
A 都重要,且相互影响。建议用GridSearchCV同时搜索。典型搜索范围:C=[0.1,1,10,100],gamma=[0.001,0.01,0.1,1,"scale"]。
Q SVM适合大数据集吗?
A 不太适合。SVM训练复杂度O(n²)到O(n³),超过100 thousand样本会非常慢。大数据集用LinearSVC(线性核)或随机森林/XGBoost。
Q SVM能输出概率吗?
A 默认不能。设置probability=True会额外训练一个Platt Scaling模型来输出概率,但训练变慢且概率不如逻辑回归校准。
Q 线性核和逻辑回归有什么区别?
A 两者都是线性分类器。区别——SVM最大化间隔(只关注边界样本),逻辑回归最大化似然(关注所有样本)。SVM在边界附近更稳健,逻辑回归概率更准。
Q SVR的epsilon参数怎么选?
A epsilon是不敏感带宽度,小于ε的误差不计入损失。典型值取目标变量的噪声水平估计。如销售预测误差在±5k USD,设ε=5。

📖 小节


📝 作业

  1. 基础题(难度⭐):用SVC(kernel="rbf")对make_moons数据集分类,对比有/无StandardScaler的accuracy。提示:Pipeline vs 直接fit。
  2. 进阶题(难度⭐⭐):用GridSearchCV搜索SVM最优参数(kernel, C, gamma),在Iris数据集上找到最佳组合。提示:Pipeline内嵌SVC + param_grid。
  3. 挑战题(难度⭐⭐⭐):实现Charlie的客户分层——生成3类客户数据,对比SVM/LogisticRegression/RandomForest的分类报告,分析哪种模型最适合边界模糊的多分类场景。提示:用classification_report对比precision/recall/f1。

← 上一课:决策树与随机森林 | 下一课:KNN与聚类 →

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏