数据在原来的坐标里线性不可分时,先把它映射到更高维的空间,在那里就分得开了。 核方法的关键是:不用真的算那个高维坐标, 只需要知道高维里两点的内积——而这个内积可以用原空间的一个函数算出来。 实测同心圆数据:原空间线性 0.5000、多项式映射后 1.0000、RBF 核 1.0000。
2.4 节的支持向量机只能画直线,2.3 节的逻辑回归也一样。 这一节解决「边界是弯的」这个普遍问题, 而且它的解法不只属于 SVM—— 「先映射再线性」这个套路,是后面 PCA、LLE、t-SNE 共同的思路来源。 数学上完整的核函数理论在 40 课 第 6 章, 这里只讲清「为什么能行」和「三个常用核怎么选」。
一、问题:直线切不开一个圈
同心圆数据是最经典的反例。 内圈半径 0.7 一类、外圈半径 2.0 另一类,任何一条直线都只能切掉一段弧,切不出整个圈。 2.3 节量过这件事:逻辑回归在这种数据上准确率 0.5075,等于瞎猜。 这个数字不是训练不足,是表达能力不够。 换个角度想:问题出在「半径」这个量上。内圈所有点的半径都小于 1,外圈都大于 1.5。 如果能直接拿半径当特征,一条竖线就切开了。 但半径不是原始坐标 x1、x2 中的一个,它是它们算出来的——√(x1² + x2²)。 「算出来的特征」就是映射的起点。
二、特征映射:把 x1、x2 换成五个新坐标
教材的做法是手工造特征。 把 (x1, x2) 换成(x1², x2², x1x2, x1, x2) 五个数,再在这个五维空间里跑线性分类器。 为什么这样就分开了? 因为半径的平方 x1² + x2² 是这五个坐标的线性组合—— 内圈点在这个组合上小、外圈大,一个平面就能切。 这一步没有增加任何新信息:五个坐标全是从原来两个数算出来的, 信息量一点没变,变的是「看它的角度」。 这是整节最该记住的一句话。 Demo 里多项式映射后测试准确率 1.0000。 但要注意:这个好成绩有运气成分,因为圆的边界正好是二次曲线,而二次特征里正好含着 x1² 和 x2²。 如果边界是三次曲线,这五个特征就不够了。 真实数据里没人知道边界长什么样,总不能一个个试。 所以需要一种「不预设形状」的映射——这就是核函数要做的事。
三、核技巧:不算坐标,只算内积
如果映射到高维只是为了让线性分类器工作,那分类器需要的其实只有一件事: 高维空间里两点的内积。 它不需要知道每个点的坐标,只需要知道「谁离谁近」。 于是有个大胆的想法:能不能绕过「先算坐标、再算内积」,直接写一个函数,输入是原空间的两个点, 输出是高维空间的内积? 能。这个函数就叫核函数。教材给的例子是最常用的 RBF 核:K(a, b) = exp(−γ|a − b|²)。 它只看两点的距离,距离越近值越接近 1,越远越接近 0。 这个函数背后对应着一个无穷维的映射——你没法把那个空间的坐标写出来, 但你可以精确算出任意两点在里面的内积。这就是「核技巧」的全部魔法。 省下的是什么?省下的是计算量。一个多项式核映射到几十万维,直接算坐标要几十万次乘法; 用核函数,一次距离计算就够了。精度一点没丢,只是换了个算法。
四、三个常用核,怎么选
教材列了三个,实际用得最多的也是这三个: 线性核——就是不加映射,内积照算。 特征维度已经很高(比如文本)时反而最好,因为高维空间里数据本来就容易线性可分。 多项式核——对应「所有 d 次项的组合」。 适合边界是光滑曲线的场景,但 d 一大,数值会爆,要注意标准化。 RBF 核(高斯核)——最通用,也是默认首选。 它只有一个参数 γ,控制「多近才算近」:γ 大,影响范围小,边界会绕着每个点画圈(过拟合); γ 小,影响范围大,边界接近直线(欠拟合)。 选核的实用顺序: 先试 RBF,效果不好再看是不是特征本身不够;如果特征已经几千维(文本),直接用线性核。 多项式核现在用得少了,因为 RBF 加调 γ 能覆盖它的大部分场景。 Demo 里还量了一个数:RBF 核下同类的平均相似度 0.4662,跨类只有 0.0513, 差了 9 倍。 这说明核函数自己就把「同类该像」编码进去了, 后面的线性分类器只是把这件事读出来而已。
五、动手 Demo:先把数据抬到高维,再用直线去切
同心圆数据,内圈半径 0.7、外圈 2.0,各 150 个。 按 2 比 1 分成训练 200、测试 100,三种做法都只在训练集上学,分数一律报测试集的。 第三种做法用的是核岭回归而不是完整的核 SVM——因为它的解只需要解一个线性方程组,代码短、结果稳。 要看的性质(核能把圆掰开)和用哪个分类器无关。
import numpy as np
def poly(P): # 手工造五个特征
x1, x2 = P[:, 0], P[:, 1]
return np.column_stack([x1 * x1, x2 * x2, x1 * x2, x1, x2])
def rbf(A, B, g): # 核:只算「两点有多近」
d = A[:, None, :] - B[None, :, :]
return np.exp(-g * (d * d).sum(axis=2))
K = rbf(Ptr, Ptr, 1.0) # 训练集自己的核矩阵
alpha = np.linalg.solve(K + 1e-3 * np.eye(len(K)), ytr)
pred = np.sign(rbf(Pte, Ptr, 1.0) @ alpha)
print("RBF 核测试准确率 %.4f" % (pred == yte).mean())
实跑输出:
--------------------------------------------------------------------
核方法:先把数据抬到高维,再用直线去切
--------------------------------------------------------------------
同心圆:内圈半径 0.7 一类、外圈半径 2.0 另一类,各 150 个点。在原来的坐标里,
**任何直线都切不开它**
——这是 2.3 节逻辑回归栽过的地方。先按 2 比 1 分成训练 200 个、测试 100 个,
三种做法都只在训练集上学,分数一律报测试集的。
【一】原空间硬切:一条直线
训练完的分界线还是一条直线,测试准确率 **0.5000**
——和瞎猜差不多,因为它只能用一条直线去切一个圈。
【二】多项式映射:手工把两个坐标变成五个
映射是 (x1, x2) → (x1², x2², x1x2, x1, x2)。原来的「圈」在新空间里变成了一个
**平面能切开的东西**——因为半径的平方 x1²加 x2² 直接就是一个坐标了。
注意这一步没有增加任何新信息,只是**换了个看数据的角度**。
支持向量机在新空间里做的还是那件事:找最宽的空隙。
【三】RBF 核:连映射都不用写,只算「两点有多近」
RBF 核 K(a, b) = exp(−γ |a − b|²),γ = 1.0。它衡量两个点有多近:重合时是 1,离远了趋于 0。
**核矩阵就是一张「谁离谁近」的表。**
做法 输入维度 准确率
----------------------------------------------------
原空间线性 2 0.5000
多项式映射后线性 5 1.0000
RBF 核 2(隐式无穷维) 1.0000
【四】核矩阵长什么样:把同类和跨类的相似度分开看
内圈内部两两相似度平均 0.4662,内圈对外圈平均 0.0513,**差了 9 倍。**
RBF 核自动把「同类该像、异类该不像」这件事编码进去了,
所以后面那个线性分类器闭着眼睛都能分开。
顺带说一句:这题多项式映射也拿了满分,因为**圆的边界正好是个二次曲线**,
而多项式特征里含着 x1² 和 x2²。真实数据里没人知道边界长什么样,
这时候 RBF 这种「不预设形状」的核更实用——代价是 γ 要自己调。
核方法的核心就一句话:**不用真的把数据搬到高维去算,只需要知道高维里两点的内积。**
而这个内积可以用原空间的一个函数算出来——这就是「核技巧」,省掉的是维度爆炸的计算量,
不是精度。
三行数字是这一节的骨架:0.5000、1.0000、1.0000。第一行是「一条直线切一个圈」,等于瞎猜; 后两行是两种「把数据抬到高维」的做法,都满分。差别不在分类器,在坐标。 多项式映射用的是五个手工特征。 注意代码里没有真的去算「半径」,而是给了 x1²、 x2²——半径的平方刚好是这两个的和,所以线性分类器自己就能拼出半径。 你不用告诉它「用半径」,只要把料给够。 RBF 那一段更极端:连特征都不造。 只算 200 乘 200 的核矩阵,解一个线性方程组,就得到 1.0000。 这个矩阵的每个元素是「两个点有多近」,整张表就是数据在高维空间里的相似度地图。 0.4662 与 0.0513 那两个数值得看两眼。 同类内部两两相似度平均 0.4662,跨类只有 0.0513。 差 9 倍意味着:核函数已经把「谁和谁一类」写在数字里了,分类器只需要找个阈值。 最后那句「多项式也满分」是个诚实的提醒:这道题多项式就够,因为边界正好是圆的。 换一道边界形状未知的题,RBF 才是稳妥选择。
30 秒实验
- 把 γ 从 1.0 改成 0.1 和 10,RBF 的测试准确率会怎么变?哪个方向是过拟合?
- 把 RBF 换成线性核(K = Ptr @ Ptr.T),会退回哪个数?
- 为什么说「多项式映射没有增加新信息」?那它凭什么让准确率从 0.5 跳到 1.0?
常见误区
- 以为核方法「一定更好」。特征维度已经很高时(文本、图像),线性核往往够用还快得多。 RBF 是多花的算力买「形状自由」,用不上就是浪费。
- 不做标准化就用 RBF。核里算的是距离,尺度大的特征会独吞这个距离,和 KNN 一模一样。 RBF 之前必须标准化。
- 把 γ 调得很大以为能「提高精度」。γ 大等于每个点只管自己周围一小圈,边界会碎成一堆小岛, 训练集满分、测试集崩盘。γ 和 k 近邻的 k 是同一类旋钮:控制「看多远」。
自测三问(点开对答案)
1. 「核技巧」到底省掉了什么? —— 省掉了「真的把数据搬到高维空间并写出坐标」这一步。 分类器只需要高维空间的内积,而核函数能从原空间的两个点直接算出这个内积, 所以维度再高也不用付计算代价。 2. 为什么多项式映射能让同心圆数据从 0.5 跳到 1.0? —— 因为圆的边界是二次曲线,而 x1²、x2² 这两个新坐标的线性组合正好能表达半径。 分类器还是线性的,只是它现在能看到「半径」这个量了。 3. RBF 的 γ 调大,模型会过拟合还是欠拟合?为什么? —— 过拟合。 γ 大意味着「只有非常近的点才算相似」,边界会绕着每个训练点画小圈,训练集完美、测试集很差。到这里,第 2 章讲的都是「用特征算分」。 2.6 节换成另一条路:不投票、不找边界,只数词出现的次数,然后乘概率。
- ☐ (本节完,下一节 2.6 算法 6:朴素贝叶斯)