核方法完全指南:从特征映射到核函数的原理与实践
2026/9/7 13:36:31 网站建设 项目流程

很多人初学机器学习时,遇到非线性分类问题都会卡在“特征映射”这一步:为什么要把数据映射到高维?映射完之后计算量爆炸怎么办?核方法(Kernel Methods)其实就是一套专门解决这类问题的数学工具。本文基于斯坦福 CS229 机器学习课程第 7 讲的内容,把核方法的前因后果、数学原理、常用核函数、实际代码和调参经验一次讲清楚,新手能看懂原理,有基础的可以直接看代码和工程建议。

什么是核方法?为什么需要它

先从一个最直观的问题入手。逻辑回归、线性回归、线性 SVM 这些模型,本质上都在寻找一个线性边界。如果训练数据本身线性不可分,比如二维平面上的环形数据和异或(XOR)模式的数据,强行用直线去切分,效果一定很差。

为了解决这个问题,最早的思路是手动构造新的特征。例如二维坐标 (x₁, x₂) 不够用,就尝试加入 x₁², x₂², x₁x₂ 等组合特征。这种做法有一个专有名词,叫特征映射(Feature Mapping),通常记为 φ(x)。特征映射的作用是把原始输入空间的数据变换到另一个特征空间,在这个新的特征空间里,原本线性不可分的数据往往变得线性可分。

但这里立刻出现两个痛点:

特征映射的组合数量是爆炸的。假设原始特征有 100 维,如果要把所有二阶组合特征都列出来,特征维度会上升到 5000 左右;三阶组合更是天文数字。计算内积时,时间和内存都不可承受。 手工设计特征需要很强的领域知识,不是每个机器学习工程师都有时间慢慢试。 核方法的核心洞察在于:很多线性模型(尤其是 SVM)在训练和预测时,并不需要显式地知道 φ(x) 本身,只需要知道样本之间的内积 ⟨φ(xᵢ), φ(xⱼ)⟩。如果我们能够找到一个函数 K(xᵢ, xⱼ),使得它直接等于某个特征空间中的内积,并且这个函数的计算成本很低,那我们就可以绕开复杂的特征映射,直接在原始输入空间里完成所有计算。这个函数就是核函数(Kernel Function)。

换句话说,核技巧(Kernel Trick)是一种“隐式升维、显式计算”的方法。你不需要真的把数据映射到高维空间,只需要计算一个形式简单的核函数,就能等价地获得高维空间中的内积结果。这种绕过方式,是核方法最精妙的地方。

从内积到核函数:数学视角的通俗理解

在斯坦福 CS229 第 7 讲中,Andrew Ng 用了一个推理链条来建立核方法,这条链条非常值得反复琢磨。为了把问题说清楚,这里用一个常见的最小二乘回归例子作为铺垫。

3.1 线性模型的求解形式

假设我们的预测目标可以写成关于输入 x 的线性组合:

h(x) = wᵀ x

在最小二乘问题中,我们希望找到参数 w 使得训练集上的误差平方和最小。这个问题的闭式解为:

w = (XᵀX)⁻¹ Xᵀ y

其中 X 是训练样本矩阵,y 是标签向量。这里的问题是:如果要把 x 替换成 φ(x),那么矩阵 X 就变成了 Φ,而 Φ 的维度可能非常大,直接求逆几乎不可行。

3.2 将解表示为训练样本的线性组合

正则化的最小二乘问题(岭回归)经过推导,可以得到一个重要结论:最优的 w 可以写成所有训练样本的线性组合:

w = Σ αᵢ xᵢ

这个结论在 SVM、核岭回归、高斯过程等许多模型中都能看到。它说明模型参数 w 实际上被训练样本张成的空间约束住了。这样一来,预测函数可以改写为:

h(x) = Σ αᵢ ⟨xᵢ, x⟩

这里的内积 ⟨xᵢ, x⟩ 是整个计算的核心。

3.3 用核函数替换内积

当我们做特征映射后,预测函数变成:

h(x) = Σ αᵢ ⟨φ(xᵢ), φ(x)⟩

这时定义核函数:

K(xᵢ, xⱼ) = ⟨φ(xᵢ), φ(xⱼ)⟩

如果这个核函数可以直接计算,而不需要显式构造 φ,那么训练和预测过程中所有关于高维特征的操作都可以被替换掉。这正是核技巧。

需要特别强调的是,并不是随便一个函数都可以当作核函数。在 CS229 中,Andrew Ng 引入了 Mercer 定理:一个对称函数 K(x, z) 如果对应的核矩阵(Gram 矩阵)在任意有限样本集上都半正定,那么它一定对应某个特征空间中的内积。实际工程中,我们通常直接使用经过理论验证的核函数,而不自己去发明。

常用核函数详解

核函数的选择直接影响模型表现,这里整理几种最经典的核函数。

4.1 线性核

K(x, z) = xᵀ z

线性核对应的就是不做特征映射的原始空间。它适用于本身线性可分的数据,优点是训练速度快、可解释性强。在文本分类这种高维稀疏场景下,线性核往往比非线性核效果更好,因为特征维度已经足够高。

4.2 多项式核

K(x, z) = (xᵀ z + c)ᵈ

其中 c 是常数项,d 是多项式次数。当 d = 2 时,它对应的特征空间中包含了所有原始特征的一次项和二次项组合。多项式核适合特征维度较低、且数据存在明显的多项式交互关系的情况。但次数 d 过大会带来严重的过拟合和计算开销。

4.3 高斯核(RBF 核)

K(x, z) = exp(-γ ||x - z||²)

高斯核也叫径向基函数核,是最常用的非线性核。它的数学含义是:两个样本越相似(距离越近),核函数值越接近 1;距离越远,值越趋向于 0。高斯核在理论上可以将数据映射到无穷维空间,因此表达能力非常强,但也非常容易过拟合。

高斯核只有一个关键参数 γ,它的取值对模型影响极大:

γ 很大时,每个样本的影响范围非常小,决策边界非常曲折,容易过拟合; γ 很小时,每个样本的影响范围很大,决策边界趋于平滑,容易欠拟合。 4.4 Sigmoid 核

K(x, z) = tanh(α xᵀ z + c)

Sigmoid 核在某些参数设置下可以模拟神经网络的行为,但并不是所有参数都满足 Mercer 条件,实际使用中不如 RBF 核稳定。

在实际选择时,如果数据量不大、特征维度中等,优先尝试 RBF 核通常是合理的。RBF 核只有一个参数,调参成本低,表达能力覆盖了线性核和其他非线性核的很多场景。

核方法如何推广到其他算法

核方法并不只属于 SVM。任何模型,只要它的目标函数和预测过程可以写成样本内积的形式,原则上都可以使用核技巧。

5.1 核 SVM

SVM 是最典型的核方法应用。原始 SVM 求解的是带约束的二次优化问题,对偶形式中目标函数只涉及训练样本之间的内积:

max Σ αᵢ - 1/2 Σ Σ αᵢ αⱼ yᵢ yⱼ ⟨xᵢ, xⱼ⟩

将内积替换为核函数后,就可以在高维特征空间中寻找最大间隔超平面,而决策函数的计算同样只依赖支持向量与待测样本的核函数值。这也是为什么 SVM 的决策只由少数支持向量决定,模型存储和推理开销相对可控。

5.2 核岭回归

岭回归的目标函数为:

min ||Φw - y||² + λ ||w||²

通过引入对偶变量,预测函数可以写成:

h(x) = yᵀ (K + λI)⁻¹ k(x)

其中 K 是训练样本间的核矩阵,k(x) 是待测样本与所有训练样本的核函数向量。这种写法避免了在高维空间中直接求解 w,非常适合非线性回归问题。

5.3 核逻辑回归

逻辑回归也可以通过核方法实现非线性分类。由于逻辑回归本身是通过梯度下降求解的,每次梯度更新都可以表示为核函数求和形式,代价是每次预测需要遍历所有训练样本,计算复杂度为 O(n),n 是样本数量。这也是核方法在大规模数据上的主要瓶颈。

5.4 核 PCA 和其他方法

PCA 要计算协方差矩阵的特征向量。在高维特征空间里,同样可以通过核矩阵的特征分解来得到主成分,实现非线性降维。这个方法称为 Kernel PCA,常用于可视化、去噪、特征提取。

欠拟合与过拟合的关键条件

用核方法做分类或回归时,模型复杂度由以下因素共同决定:

核函数本身的表达能力。线性核表达能力最弱,RBF 核表达能力最强。 核参数。以 RBF 核的 γ 为例,γ 越小,模型越平滑,越容易欠拟合;γ 越大,模型越复杂,越容易过拟合。 正则化参数。在 SVM 中,参数 C 控制对误分类的惩罚力度。C 越小,模型越平滑,允许更多错分;C 越大,模型越严格贴合训练数据。 在实际项目里,欠拟合和过拟合的判断不能只看训练集准确率。更需要结合验证集的错误率变化来判断:

训练集和验证集误差都很高,说明欠拟合,需要增加模型复杂度; 训练集误差很低、验证集误差很高,说明过拟合,需要降低复杂度或增加正则化。 实验代码:用 scikit-learn 实现核 SVM 与可视化

为了把前面的理论落到实际,下面用一个完整的 Python 示例,展示核 SVM 在非线性分类数据上的表现,以及不同参数对决策边界的影响。

6.1 创建示例项目结构

本文示例采用以下结构:

kernel-method-demo/ ├── data.py # 构造模拟数据集 ├── train.py # 训练核SVM并输出指标 ├── plot_boundary.py # 可视化决策边界 └── requirements.txt # 依赖文件

6.2 安装依赖

需要安装 Python 3.8 以上的环境,以及 numpy、matplotlib、scikit-learn。可以使用 pip 安装:

pip install numpy matplotlib scikit-learn

版本需要根据你的项目实际情况调整,本文示例以常见环境为例,重点演示配置思路。

6.3 构造模拟数据集

使用 scikit-learn 自带的 make_moons 函数生成一个典型的非线性可分数据集,这个数据集形状像两个月牙,线性模型无法有效分类。

# 文件路径:kernel-method-demo/data.py import numpy as np from sklearn.datasets import make_moons def load_moons_data(n_samples=300, noise=0.15, random_state=42): X, y = make_moons(n_samples=n_samples, noise=noise, random_state=random_state) # scikit-learn 的 SVM 要求标签为 -1 和 1,这里做一个转换 y = np.where(y == 0, -1, 1) return X, y

make_moons 返回的原始标签是 0 和 1,为了方便观察 SVM 的决策函数,这里统一转换成 -1 和 1。

6.4 训练核 SVM 并评估

下面这段代码训练三种不同核函数的 SVM,并在同一个测试集上比较准确率和支持向量数量。

# 文件路径:kernel-method-demo/train.py import numpy as np from sklearn.svm import SVC from sklearn.model_selection import train_test_split from data import load_moons_data X, y = load_moons_data() X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3, random_state=42 ) kernels = { "linear": SVC(kernel="linear", C=1.0), "poly_3": SVC(kernel="poly", degree=3, C=1.0), "rbf_default": SVC(kernel="rbf", gamma="scale", C=1.0), "rbf_gamma_0.1": SVC(kernel="rbf", gamma=0.1, C=1.0), "rbf_gamma_10": SVC(kernel="rbf", gamma=10, C=1.0), } for name, model in kernels.items(): model.fit(X_train, y_train) train_acc = model.score(X_train, y_train) test_acc = model.score(X_test, y_test) n_sv = len(model.support_) print(f"{name:>16} | train_acc={train_acc:.4f} | test_acc={test_acc:.4f} | n_sv={n_sv}")

运行结果类似下面这样,不同随机种子和参数下数值会有波动:

linear | train_acc=0.8714 | test_acc=0.8778 | n_sv=71 poly_3 | train_acc=0.9143 | test_acc=0.9111 | n_sv=76 rbf_default | train_acc=1.0000 | test_acc=0.9778 | n_sv=49 rbf_gamma_0.1 | train_acc=0.9524 | test_acc=0.9333 | n_sv=35 rbf_gamma_10 | train_acc=1.0000 | test_acc=0.9000 | n_sv=201

从结果中可以看到两个重要现象:

线性核在非线性数据上的测试准确率最低,说明模型表达能力不足,处于欠拟合状态; RBF 核在默认参数下表现不错,但如果将 γ 调到 10,虽然训练集准确率几乎为 100%,测试准确率反而下降,这就是过拟合的直接体现。 6.5 可视化决策边界

下面这段代码将不同参数的 RBF 核 SVM 决策边界画出来,可以更直观地理解 γ 对模型复杂度的影响。

# 文件路径:kernel-method-demo/plot_boundary.py import numpy as np import matplotlib.pyplot as plt from sklearn.svm import SVC from data import load_moons_data X, y = load_moons_data() def plot_decision_boundary(model, X, y, ax, title): x_min, x_max = X[:, 0].min() - 0.5, X[:, 0].max() + 0.5 y_min, y_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5 xx, yy = np.meshgrid( np.linspace(x_min, x_max, 300), np.linspace(y_min, y_max, 300) ) Z = model.predict(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) ax.contourf(xx, yy, Z, cmap=plt.cm.RdBu, alpha=0.6) ax.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.RdBu, edgecolors="k", s=20) ax.set_title(title) ax.set_xlim(x_min, x_max) ax.set_ylim(y_min, y_max) fig, axes = plt.subplots(1, 3, figsize=(15, 4)) gamma_values = [0.1, 1.0, 10.0] for ax, gamma in zip(axes, gamma_values): model = SVC(kernel="rbf", gamma=gamma, C=1.0) model.fit(X, y) plot_decision_boundary(model, X, y, ax, f"gamma={gamma}") plt.tight_layout() plt.savefig("boundary_comparison.png", dpi=150) plt.show()

运行这段代码后,你会看到:

γ = 0.1 时,决策边界非常平滑,有些交叉区域无法分对,接近欠拟合; γ = 1.0 时,决策边界能较好地贴合数据形状,泛化表现良好; γ = 10.0 时,决策边界变得极其曲折,每一个单独样本周围都形成独立的决策区域,明显过拟合。 6.6 自定义核函数示例

scikit-learn 允许传入自定义核函数。下面演示如何用 Python 定义一个实现高斯核的函数,并传入 SVM 训练。

# 文件路径:kernel-method-demo/custom_kernel.py import numpy as np from sklearn.svm import SVC from sklearn.model_selection import cross_val_score from data import load_moons_data def rbf_kernel(X, Y, gamma=1.0): """ 自定义高斯核函数。 X: shape (n_samples_X, n_features) Y: shape (n_samples_Y, n_features) 返回核矩阵 shape (n_samples_X, n_samples_Y) """ X = np.asarray(X) Y = np.asarray(Y) # 对于每个样本,计算平方欧氏距离 # ||x - z||^2 = ||x||^2 + ||z||^2 - 2 x·z XX = np.sum(X ** 2, axis=1).reshape(-1, 1) YY = np.sum(Y ** 2, axis=1).reshape(1, -1) XY = np.dot(X, Y.T) sq_dists = XX + YY - 2 * XY return np.exp(-gamma * sq_dists) X, y = load_moons_data(n_samples=200) model = SVC(kernel=lambda X, Y: rbf_kernel(X, Y, gamma=0.5)) scores = cross_val_score(model, X, y, cv=5) print(f"自定义RBF核 SVM交叉验证准确率: {scores.mean():.4f} (+/- {scores.std():.4f})")

在自定义核函数时,需要注意两个问题:

核函数接收的 X 和 Y 不一定是原始训练数据,scikit-learn 内部可能传入不同形状的矩阵,必须保证函数能正确处理任意数量的样本; 核矩阵必须满足对称性和半正定性,否则训练过程会报错或结果异常。 工程实现中的常见问题与排查思路

核方法在实际项目中会遇到一些典型的坑,这里列出最常见的几种。

问题现象常见原因解决思路
训练时间极长样本量过大,核矩阵计算与存储开销为 O(n²)改用线性核、抽样训练、使用近似核方法或随机傅里叶特征
训练集准确率高但测试集差核参数过拟合,比如 RBF 核的 γ 过大,或 SVM 的 C 过大调低 γ 或 C,使用交叉验证选择参数
训练集和测试集准确率都低模型表达能力不足或特征未标准化检查是否使用 RBF 核,检查特征缩放情况
预测速度慢支持向量数量过多,预测需要计算大量核函数调高 C 或 γ 提高正则化,减少支持向量;或考虑换模型
自定义核函数时报错核函数没有按 scikit-learn 的签名实现,或核矩阵不满足正定性检查输入输出形状,验证核矩阵对称且对角元素为正
数据量太大内存不足核矩阵存储占用过高使用 SGDClassifier 配合近似核特征,或使用 MiniBatchKMeans 等替代方案

其中,特征标准化是一个非常容易被忽略的细节。RBF 核函数使用的是样本之间的欧氏距离,如果不同特征的量纲差异很大,距离计算会被数值较大的特征主导,模型效果极不稳定。因此使用核方法前,强烈建议先对特征做标准化处理。

from sklearn.preprocessing import StandardScaler from sklearn.pipeline import make_pipeline model = make_pipeline( StandardScaler(), SVC(kernel="rbf", gamma="scale", C=1.0) )

把标准化放进 Pipeline 中有两个好处:训练时不会忘记做标准化;预测时自动化应用同一套标准化参数,避免数据泄露。

最佳实践与工程建议

核方法在中小型数据集上表现优异,但在大数据场景下会遇到明显的计算瓶颈。基于大量实际项目经验,这里整理几条核心建议。

7.1 优先用线性模型做基线

遇到一个新的分类或回归任务,不要急着上 RBF 核。先用线性模型跑一遍,记录准确率、训练时间、推理时间,作为后续所有实验的参照。如果线性模型效果已经满足需求,就没有必要引入非线性模型。

7.2 核参数搜索要有范围意识

用网格搜索寻找 RBF 核的 γ 和 SVM 的 C 时,建议在指数级刻度上搜索,例如:

from sklearn.model_selection import GridSearchCV param_grid = { "svc__C": [0.1, 1, 10, 100], "svc__gamma": [0.01, 0.1, 1, 10], } grid = GridSearchCV(model, param_grid, cv=5, scoring="accuracy", n_jobs=-1) grid.fit(X_train, y_train) print(grid.best_params_)

要注意的是,网格搜索只是调参的一种手段,不能代替对模型可解释性的判断。如果搜索出来的参数组合非常极端,比如 C = 1000 且 γ = 100,说明数据本身可能存在问题,或者核方法并不适合这个任务。

7.3 大规模数据使用近似核方法

当样本量超过数万时,精确计算核矩阵往往不可行。工程上常用的替代方案是使用随机傅里叶特征(Random Fourier Features)或 Nyström 方法,先对原始特征做近似映射,再配合线性模型训练。scikit-learn 中的 RBFSampler 就是随机傅里叶特征的一种实现。

from sklearn.kernel_approximation import RBFSampler from sklearn.linear_model import SGDClassifier feature_map = RBFSampler(gamma=0.5, n_components=100, random_state=42) X_transformed = feature_map.fit_transform(X_train) clf = SGDClassifier(loss="hinge", max_iter=1000, random_state=42) clf.fit(X_transformed, y_train)

这种方法的优势是训练复杂度与样本量近似线性,非常适用于大规模数据。

7.4 重视可解释性

核方法的决策函数通常很难直观解释。在需要向业务方解释模型逻辑的场合,可以训练一个线性模型作为近似解释器,例如在核 SVM 预测结果的附近,用 LIME 或 SHAP 分析局部特征贡献。不要指望对方能理解高维映射的概念。

7.5 留意标签平衡问题

SVM 在不平衡数据上表现不稳定。如果正负样本比例严重失衡,建议对少数类样本设置更高的惩罚权重。scikit-learn 的 SVC 提供了 class_weight="balanced" 参数,可以根据类别频率自动调整权重。

在 scikit-learn 中的参考实现

为了让读者快速上手,这里再整理一段完整可直接运行的代码,综合了数据生成、标准化、网格搜索和评估。将这段代码保存为 kernel_svm_full.py 后运行即可。

# 文件路径:kernel_svm_full.py import numpy as np from sklearn.datasets import make_moons from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.preprocessing import StandardScaler from sklearn.pipeline import make_pipeline from sklearn.svm import SVC from sklearn.metrics import classification_report # 1. 生成数据 X, y = make_moons(n_samples=500, noise=0.2, random_state=42) y = np.where(y == 0, -1, 1) X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y ) # 2. 构建带标准化的 SVM 管道 pipeline = make_pipeline( StandardScaler(), SVC(kernel="rbf") ) # 3. 网格搜索 param_grid = { "svc__C": [0.1, 1, 10, 100], "svc__gamma": [0.01, 0.1, 1, 10], } 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_:.4f}") # 4. 测试集评估 y_pred = grid.predict(X_test) print(classification_report(y_test, y_pred, target_names=["class -1", "class 1"]))

这段代码几乎是核 SVM 任务的一个最小工业模板,可以直接替换成自己的数据集。

从理论到实践的学习建议

核方法是一个值得反复深入钻研的主题。掌握基本应用之后,建议按下面的顺序继续学习:

第一,深入理解对偶问题。CS229 第 7 讲的重点之一是从原问题到对偶问题的推导,这部分数学基础直接决定了后续能否理解 SVM 软间隔、KKT 条件等更复杂的概念。

第二,学习正则化与核方法的统一视角。核岭回归、高斯过程、支持向量回归、Kernel PCA 这些方法拥有相似的理论框架,放在一起对比学习效率会高很多。

第三,动手实现一个简单的核感知机或核 SVM。不要只调包。自己手写一个核矩阵计算和预测函数,即使是几十行代码,也能让你对内积替换这个核心思想有更强烈的体会。

第四,关注核方法在现代深度学习中的延伸。深度学习模型本身就相当于在特征层面做组合,而神经正切核(Neural Tangent Kernel)则探讨了无限宽神经网络与核方法的联系。这是一个非常活跃的研究方向,也是检验你是否真正理解核方法的试金石。

在 CS229 这门课中,核方法不仅是 SVM 的配套技巧,更是一种贯穿始终的建模思想:与其费尽心思设计高维特征,不如用核函数隐式地表达特征空间中的相似性。理解了这个变化,你对机器学习模型的认识会明显上一个台阶。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询