查看全课大纲(第 73 / 82 节)
- 1.函数与数据泛化
- 2.向量:从几何直觉到高维空间
- 3.矩阵与张量
- 4.特征值与特征向量:矩阵变换的不动方向
- 5.凸函数:从向量求导的矩阵记号到好优化的函数形状
- 6.概率与统计:机器学习的数学基础
- 7.独立性与随机变量:贝叶斯公式与二项分布
- 8.期望、方差与协方差:随机变量的数字画像
- 9.联合概率:当一条轴不够用的时候
- 10.概率分布(一):从伯努利到伽马函数
- 11.概率分布(二):贝塔、泊松、正态与两个贝叶斯故事
- 12.机器学习的模型:找输入与输出的关系
- 13.机器学习的应用
- 14.过拟合
- 15.机器学习的分类
- 16.有监督学习:从房价预测说起
- 17.损失函数
- 18.梯度下降(上):更新规则与学习速率
- 19.梯度下降(2)
- 20.牛顿方法
- 21.KNN简介
- 22.距离测算
- 23.朴素贝叶斯
- 24.朴素贝叶斯的实际应用
- 25.信息熵:决策树构建的度量基础
- 26.信息增益与决策树的构建
- 27.ID3算法
- 28.决策树节点的划分
- 29.CART树
- 30.Bagging
- 31.Boosting:自适应提升算法
- 32.Gradient Boosting
- 33.线性模型:回归与分类的同一副骨架
- 34.最小二乘:把最优参数直接解出来
- 35.最小二乘法的几何与概率视角
- 36.极大似然:给最小二乘一个概率出身
- 37.逻辑回归(1):把线性模型接到分类上
- 38.逻辑回归(2):损失函数与多分类
- 39.---- 手造数据: 5 个样本, 2 个特征; x2 几乎 = 2*x1 (偏差手工指定, 无随机) ----
- 40.讲师例: 向量 "23014" -- 三把范数尺子量同一个向量
- 41.优化方法(1):坐标下降与前向选择
- 42.优化方法(2):前向策略与最小角回归
- 43.拉格朗日乘子法(1):从无约束到等式约束
- 44.拉格朗日乘子法(2):等式约束下的平行条件与拉格朗日函数
- 45.拉格朗日乘子法(3):不等式约束与 KKT 条件
- 46.最大间隔:把分类问题变成优化问题
- 47.拉格朗日对偶问题:把 w 和 b 全部换成 α
- 48.支持向量:边界上的少数派
- 49.SVM 计算过程:一笔到底算完,再走进核方法
- 50.贝叶斯公式:概率即信念
- 51.隐含变量和概率模型:给看不见的原因建模
- 52.EM 算法:期望与最大化的迭代
- 53.琴生不等式:EM 的数学钥匙
- 54.三个硬币问题:EM 的复盘与衔接
- 55.高斯混合模型:用隐变量解释双峰数据
- 56.隐马尔可夫模型
- 57.隐马尔可夫模型(2):前向算法与动态混合模型
- 58.隐马尔可夫模型在 NLP 中的运用
- 59.EM 算法:把「为什么收敛」推到底
- 60.HMM 在 NLP 中的运用:从分词到机器翻译
- 61.HMM 参数估计:Baum-Welch 的三块拉格朗日
- 62.高维下的高斯模型
- 63.主题模型:从词袋到隐含主题
- 64.Dirichlet 分布(1)
- 65.Dirichlet 分布(2)
- 66.统计学习内容回顾
- 67.K-means 算法
- 68.PCA 降维
- 69.SVD 降维
- 70.从聚类到流形
- 71.局部线性嵌入
- 72.随机邻域嵌入:SNE 与 t-SNE
- 73.无参模型:让数据自己说话
- 74.高斯过程:函数空间里的正态分布
- 75.高斯过程(2):噪声、正则化与核的线性组合
- 76.神经网络简介:从感知器到自编码器
- 77.反向传播:把误差一层层传回去
- 78.卷积神经网络(CNN):让特征自己学出来
- 79.循环神经网络(RNN):给网络装上记忆
- 80.深度学习回顾:静态一类,动态一类
- 81.增强学习(1):蒙特卡洛、树搜索与 Q-learning
- 82.强化学习(2):从乌鸦吃核桃到井字棋的 value 回传
无参模型:让数据自己说话
约 31 分钟
小象实战讲义 · 机器学习算法精讲
前面十七章里我们学的模型,绝大多数都先给数据「戴了一顶假设的帽子」——线性也好、正态也好、混合模型也好,先把函数形式定下来,再学参数。这一章换一条路:无参模型(nonparametric model)。它不预设数据的整体形状,让数据自己把自己的分布、自己的规律「说」出来——讲师的原话是 data talk for themselves,数据自己给自己说话。我们会从最熟悉的 KNN 出发,一路推广到核密度估计 KDE 与 Nadaraya-Watson 核回归,最后看到一条带「置信带子」的连续拟合曲线是怎么被数据「自己」学出来的。
💡 核心导读
- 无参不等于没有参数:KNN 也有个 k——讲师亲自回答过这个疑问:判别一个点属于哪类,关键是它周围的邻居,而不是 k;我们从不「训练」k。
- 从邻域均值到全局加权:KNN 取最近 k 个点的均值 → 给邻居配权重(谁近谁权大)→ 干脆把所有数据点都考虑进来,权重由核函数按距离给出。
- 核密度估计(KDE):在每个数据点上放一个固定小方差的小高斯,全部累加再归一化——不假设整体分布,直接得到 。
- Nadaraya-Watson 核回归:预测值 = 所有点 的加权平均,权重是核函数 ——分子加权、分母归一化。
- δ(德尔塔)与带子:核的宽窄 δ 决定拟合曲线的平滑程度,也决定那条「概率带子」的宽窄。
开场:机器学习的大地图
在进入正题之前,讲师把这门课在大地图上的位置又描了一遍。最终大纲里本来还想讲 concept learning(概念学习)——但讲师坦承当时想大纲的时候「没有那么系统」,所以今天的主要内容是 nonparametric model(无参模型),这是机器学习特别重要的一部分。
还有几块内容「非常可惜没有时间」讲,但值得记住名字,因为它们都是机器学习版图上的重要板块:
- 度量学习(metric learning):尤其是最近 deep metric learning 有很多新的工作出来——我们在 5.2 节说过,「距离」本身就是可以自己定义、自己学的;
- 迁移学习(transfer learning);
- 深度学习(deep learning):工作特别多,尤其是对抗网络,还有各种 CNN、RNN、LSTM;
- Zero Shot Learning(零样本学习):那些可能会以深度学习为基础;
- 强化学习(reinforcement learning):第二十章会正式讲到;
- 甚至还有更早的遗传算法、遗传编程(genetic programming)——机器学习最早实际上把遗传算法和遗传编程都放到自己的范畴里来了。最近还有一些新工作在研究「怎么自动学习模型、机器怎么自动进行机器学习」,也就是 learning to learn——学习「如何学习」:我们正常是 set up 一个 model,那能不能有一个 meta learning 的 approach,站到更高一层的 learning process 上去?
所以讲师给这门课的定位是:一个 introduction to machine learning——从最基础的数学,讲到今天一些稍稍新一点的概念(昨天讲到 t-SNE,17.3 节,就算稍稍新的工作了)。
有参模型:我们一直在用的假设
先回顾我们一直是怎么做监督学习的。给定了数据 ,我们想学习它们所对应的函数关系——一个映射 ,输出的是 。这种情况下,我们一般都假设这个函数是一个有参模型(parametric model):,这里的 就是 parameters,我们的参数。
比如最简单的 ——线性模型:
所以很容易表示成 的形式。有了参数,接下来就是大家熟悉的老三样:调整参数——构造 cost function(损失函数),然后求它对 的梯度,用梯度下降去优化。这些都是我们以前已经学过的基本思想。
概率模型也一样:给定 的时候,一般也假设 服从一个有参数的分布——比如认为它是正态分布,那参数就是 和 。尤其我们后来学到的生成模型(generative model),里边的复杂结构参数更多:拿大家已经很熟的隐马尔可夫模型来说(13.3 节),它的释放矩阵 、状态转移矩阵 ——这些全都是模型的参数。
所以以前的这些模型,可以统一简单地认为都叫 parametric model(parameter 的形容词形式)。
无参模型:KNN 与「k 之问」
那今天要说的 nonparametric model 是什么?大家能想象得到:我们不需要任何的这种模型——或者说,模型的参数不是它最重要要学习的部分;最需要学习的东西,主要根据数据本身的情况来决定。上次课讲的那些降维方式(第十六、十七章),其实很多都属于无参模型。
最有代表性的例子就是 KNN。现在有很多数据,我们没有任何其他模型去假设这些数据是什么。给定了其中某一个点,想知道这个点最近的邻居都是什么——把这三个点画进来,然后根据这些数据的投票(voting)值:它是一个正、它也是一个正、那一个是一个负——那我们就把它认为是正。也就是说,我们并不想用已知的数据去训练模型里的参数,而是通过这些数据直接得到的值来进行分类或者预测。
这里有一个几乎必被问到的问题,讲师当年课堂上就替大家问了出来:「那 KNN 不是还得指定一个 k 吗?k 不就代表要找最近几个点吗?这些点难道不就是参数吗?怎么还说它是非参数模型呢?」
讲师的回答值得原样记住:我们最后判别这个点属于哪一个类别,关键的部分是它周围这些邻居的情况,而不是 k 的选择。所以它虽然有参数 k,但我们不是想通过已知的训练数据来训练 k 的多少、来达到分类的目的——k 是开工前就定好的「规则」,不是从数据里学出来的「结论」。这就是无参模型的「无参」二字真正指的东西。(5.1 节练习里我们论证过同一件事,可以对照。)
从最近邻均值到全局加权
KNN 回顾:预测问题的标准做法
来看回归版本。假设数据沿着时间有这样一个顺序(比如时间序列),给定数据 和 的对应: 对应 。现在来了一个新的数据 ,想知道它所对应的 应该等于多少——这是一个很 classical、很标准的预测问题。
用 KNN 怎么做:在 的这些训练数据里,找到离 最近的邻居。比如 :找到三个最近的邻居,求这三个点 的均值——这就是 的最好估计。 取 5,就是五个点的均值——在 方向上取均值。这些都是我们已经学过的。
降维思想的回响
这里讲师专门停下来回扣了昨天降维的三部曲,因为这个思想一步步深化的过程,跟今天要做的事情是同一个套路:
- Isomap:找到它最近的这些点,把这些点的位置关系在新的空间里保留;
- LLE:看这些点到它们之间相对的距离,距离在新的空间得以保留;
- SNE:不只是最近邻域几个点之间的关系,希望这个点跟所有点之间的位置关系在新的空间得以保留。
处理的考虑一步步泛化——今天对 KNN 的推广,走的正是同一条路。
三步泛化
KNN 最早的做法,取 个最近邻、每个邻居求均值,写成公式( 属于 的邻居集合):
第一步泛化:邻域里配权重。 均值可以用加权平均代替——给邻居们配权重 ,谁离 更近,谁的权重更大。注意普通的 相当于默认所有邻居权重都一样大;而 已经考虑了每一个的权重、是可以调的——这正是「考虑周围这些 之间的权重」的意思。
第二步泛化:干脆不要邻域。 刚才的权重都只作用在邻域里——那不在邻域的点,把所有的数据全考虑进来,不也一样吗? 从 1 到 全部参与,每个点到 都有一个距离:距离越大权重越小,距离越小权重越大。
第三步:需要一个好的权重函数。 用什么函数来表述「远近距离」与「权重」之间的关系?这就引出了核函数(kernel function)。
核函数是什么样的东西?举个最简单的例子——高斯核。 起到的作用,就是衡量这两者之间的距离有多远。我们希望它满足这样的性质:
- ——自己跟自己——应该等于一个比较大的值,比如等于 1;
- ——当 的距离趋于无穷大的时候。
也就是说,它构造的是相似度:离它越近(或它自己本身),相似度构成最大(构造成 1);离得特别远,就构造成 0。只要满足这样一些函数关系的,就可以当成一个 kernel function——高斯核是最常用的一个。
把这三步写成代码对比一下。数据用一组手工构造的时间序列(讲义设定:先升后降的 9 个点,模拟讲师黑板上的草图),查询点 :
import math
# 时间序列数据(讲义设定: 先升后降的 9 个手工点, 模拟讲师黑板草图)
data = [(0, 0.2), (1, 0.8), (2, 1.5), (3, 1.9), (4, 1.7), (5, 1.2), (6, 0.5), (7, 0.1), (8, -0.3)]
def knn_mean(xq, data, k):
"""KNN 回归: 取最近 k 个邻居 y 的均值"""
ds = sorted(data, key=lambda p: abs(p[0] - xq))
return sum(y for _, y in ds[:k]) / k
def nw(xq, data, delta):
"""Nadaraya-Watson: 所有点按高斯核加权, 分母归一化"""
w = [math.exp(-((xq - x) ** 2) / (2 * delta ** 2)) for x, _ in data]
return sum(wi * y for wi, (_, y) in zip(w, data)) / sum(w)
x_star = 2.6
print(f"查询点 x* = {x_star}, 数据 y 全局均值 = {sum(y for _, y in data) / len(data):.4f}")
print(f" KNN k=3 最近邻均值 = {knn_mean(x_star, data, 3):.4f} (邻居: x=3,2,4)")
print(f" KNN k=5 最近邻均值 = {knn_mean(x_star, data, 5):.4f} (邻居: x=3,2,4,1,5)")
print(f" NW 高斯核全局加权 delta=1.0 = {nw(x_star, data, 1.0):.4f}")
print(f" NW 高斯核全局加权 delta=3.0 = {nw(x_star, data, 3.0):.4f}")
print()
for x, y in data:
w = math.exp(-((x_star - x) ** 2) / (2 * 1.0 ** 2))
print(f" x={x} y={y} 权重 = {w:.4f}")查询点 x* = 2.6, 数据 y 全局均值 = 0.8444
KNN k=3 最近邻均值 = 1.7000 (邻居: x=3,2,4)
KNN k=5 最近邻均值 = 1.4200 (邻居: x=3,2,4,1,5)
NW 高斯核全局加权 delta=1.0 = 1.5740
NW 高斯核全局加权 delta=3.0 = 1.0973
x=0 y=0.2 权重 = 0.0340
x=1 y=0.8 权重 = 0.2780
x=2 y=1.5 权重 = 0.8353
x=3 y=1.9 权重 = 0.9231
x=4 y=1.7 权重 = 0.3753
x=5 y=1.2 权重 = 0.0561
x=6 y=0.5 权重 = 0.0031
x=7 y=0.1 权重 = 0.0001
x=8 y=-0.3 权重 = 0.0000看权重表这一列,就是「距离越大权重越小」的直接兑现:离 最近的 权重 0.9231 最大, 次之,一远( 以后)权重就掉到千分位以下——但注意没有谁是真正的 0,这正是「全局加权」与「KNN 只取 k 个」的差别。再看四个预测值的对比:k=3 的均值 1.7000 只看了 3 个点,k=5 降到 1.4200(把两个更远的点平均了进来),而 NW 全局加权给出 1.5740——介于两者之间,因为它让近处的点大声说话、远处的点小声说话,而不是一刀切。δ 放大到 3.0 之后预测变成 1.0973,明显向全局均值 0.8444 靠拢——核太宽时大家权重都差不多,预测就被拉向全局平均。
核密度估计:每个数据点放一个小高斯
现在看一个更基础的问题:给定一堆数据点 ,不假设任何参数分布,直接估计它们的概率密度 ?这就是 kernel density estimation(核密度估计),有时直接叫 KDE。它是一种 nonparametric 方法:不基于参数,基于数据本身,根据数据本身学习出概率分布的估计(讲师口译 density 为「浓度」)。
先直观理解。给了一堆数据,它们自然存在的状态画出来,是一个 empirical distribution(经验分布)——我们没有假设它们服从正态、泊松或者其他任何东西。把概率分布尽量画成离散的情况:数据密的地方柱子高、疏的地方柱子矮;如果认为它是连续的,就可能逼近一条连续的曲线。
那给定这些数据,想知道下一个数据采样的时候应该在什么位置,两条路线的分野就在这里:
- parametric 路线:先假设它是一个什么分布——比如说是一个三个高斯的混合模型(GMM,13.2 节)——然后去估计三个高斯的不同参数,有了参数之后再进行采样,找下一个值;
- nonparametric 路线:不假设这些数据是哪生成的。对每一个数据,考虑到它也许有个噪音——每一个数据有可能就是一个正态的分布:以这个数据为中心、给定一个固定的小方差。把这些小高斯不断组合到一起,就得到一条比经验分布高一些、特别平滑一些的连续分布。
这就是估计出来的 。注意两件事:第一,把这些高斯累加到一起之后,还要做一个 normalization(归一化);第二,我们并没有假设这些数据整体成什么分布——被这些小高斯所起到的作用,就是平滑掉数据与数据之间的噪音。整个 是完全基于数据的 empirical 分布画出来的,所以这是一种 nonparametric 模型。
数学形式很简单(高斯核,带宽 ):
用代码把它跑出来(数据是两团各三个点,讲义设定):
import math
def kde(xq, pts, delta):
"""核密度估计: 每个数据点放一个固定小方差的高斯, 累加后除以 N"""
N = len(pts)
c = 1.0 / (delta * math.sqrt(2 * math.pi))
return c * sum(math.exp(-((xq - xi) ** 2) / (2 * delta ** 2)) for xi in pts) / N
pts = [-2.0, -1.5, -1.0, 1.0, 1.5, 2.0] # 两团各三个点(讲义设定)
print("KDE (delta=0.8):")
for xq in (-1.5, 0.0, 3.0):
print(f" p({xq:+.1f}) = {kde(xq, pts, 0.8):.4f}")
# 归一化验证: 每个小高斯积分都是 1, 平均之后积分仍应是 1(梯形法数值积分)
acc = 0.0
step = 0.01
xq = -8.0
while xq < 8.0:
acc += (kde(xq, pts, 0.8) + kde(xq + step, pts, 0.8)) * step / 2
xq += step
print(f" 数值积分 [-8,8] = {acc:.4f} (归一化的直接验证)")KDE (delta=0.8):
p(-1.5) = 0.2206
p(+0.0) = 0.1121
p(+3.0) = 0.0560
数值积分 [-8,8] = 1.0000 (归一化的直接验证)三个位置读一遍这条密度曲线:数据点身上()密度最高,0.2206——附近三个小高斯都在抬它;两团之间()是个低谷,0.1121——离哪团都不近;数据边缘之外()只剩衰减的尾部,0.0560。「下一个数据大概率落在哪」这个问题,就这样不借助任何分布假设被回答了。最后那行数值积分 1.0000,是「累加之后要归一化」这句话的机器验证:每个小高斯积分都是 1,平均之后整条 曲线积分仍然是 1——它是一条货真价实的概率密度。
Nadaraya-Watson 核回归
回到回归问题:给定很多 的数据、 也有对应的数据,怎么用核函数估计 更好的值?把 KNN 模型再泛化一步,就得到本节的主角。构造一个估计函数 :
讲师板书到这里特意把这个名字一个字母一个字母拼了出来:N-A-D-A-R-A-Y-A——Nadaraya(现场拼得磕磕绊绊)——Watson,Nadaraya-Watson kernel。它描述的事情其实非常简单:每一个点到查询点 的距离,当成一个权重;这个权重乘上它对应的 ;所有底部(分母)做一个 normalization 归一化——这就是 的最好估计。换句话说:对 的估计,要考虑所有的点对 的贡献——贡献各有大小,把对应的 乘上各自的贡献,再做一次加权的均值,就是 的结果。
刚才说的 kernel function 完全可以用高斯核来建模:
(δ 读作德尔塔,就是核的宽窄。)它俩相同()的时候,指数是 0,——权重最大;距离特别大的时候,高斯的尾巴特别长,趋于 0——权重消失。这正是上一节构造核函数时要求的性质。
扫出一条连续的曲线
还有一个漂亮的收尾动作。给定 找到 ,这没有任何问题;那把 从 到 做一个循环,每一个点都取一个值——每个 都有对应的 ——这样我们几乎就可以学出来一条连续的线。讲师说得很诚实:这条线不是百分之百连续,但是把取值的间距取得特别小的时候,可以逼近一条连续的线。这条线,就是给定这些数据时最好的拟合估计。
import math
# 数据与上一节相同(讲义设定的时间序列), 此块自包含重写
data = [(0, 0.2), (1, 0.8), (2, 1.5), (3, 1.9), (4, 1.7), (5, 1.2), (6, 0.5), (7, 0.1), (8, -0.3)]
def nw(xq, data, delta):
w = [math.exp(-((xq - x) ** 2) / (2 * delta ** 2)) for x, _ in data]
return sum(wi * y for wi, (_, y) in zip(w, data)) / sum(w)
# x* 从 min 到 max 扫描(间距 0.5, 取得越小越接近连续)
print("x* 从 min(xi) 到 max(xi) 扫描出的拟合曲线:")
for i in range(17):
xq = i * 0.5
print(f"x*={xq:4.1f} y*(delta=1.0)={nw(xq, data, 1.0):+.4f} y*(delta=3.0)={nw(xq, data, 3.0):+.4f}")x* 从 min(xi) 到 max(xi) 扫描出的拟合曲线:
x*= 0.0 y*(delta=1.0)=+0.5190 y*(delta=3.0)=+1.0308
x*= 0.5 y*(delta=1.0)=+0.6820 y*(delta=3.0)=+1.0581
x*= 1.0 y*(delta=1.0)=+0.8931 y*(delta=3.0)=+1.0798
x*= 1.5 y*(delta=1.0)=+1.1335 y*(delta=3.0)=+1.0946
x*= 2.0 y*(delta=1.0)=+1.3659 y*(delta=3.0)=+1.1013
x*= 2.5 y*(delta=1.0)=+1.5472 y*(delta=3.0)=+1.0990
x*= 3.0 y*(delta=1.0)=+1.6436 y*(delta=3.0)=+1.0868
x*= 3.5 y*(delta=1.0)=+1.6402 y*(delta=3.0)=+1.0645
x*= 4.0 y*(delta=1.0)=+1.5403 y*(delta=3.0)=+1.0322
x*= 4.5 y*(delta=1.0)=+1.3603 y*(delta=3.0)=+0.9906
x*= 5.0 y*(delta=1.0)=+1.1246 y*(delta=3.0)=+0.9407
x*= 5.5 y*(delta=1.0)=+0.8618 y*(delta=3.0)=+0.8839
x*= 6.0 y*(delta=1.0)=+0.6010 y*(delta=3.0)=+0.8220
x*= 6.5 y*(delta=1.0)=+0.3660 y*(delta=3.0)=+0.7566
x*= 7.0 y*(delta=1.0)=+0.1709 y*(delta=3.0)=+0.6894
x*= 7.5 y*(delta=1.0)=+0.0198 y*(delta=3.0)=+0.6219
x*= 8.0 y*(delta=1.0)=-0.0900 y*(delta=3.0)=+0.5554两列对照着读。δ=1.0 那列:曲线从 0.52 一路爬到 3.0 附近的峰顶 1.6436,再缓降到 −0.09——先升后降的趋势被数据自己「说」了出来,峰的位置跟手工数据( 处 最高)严丝合缝。两个细节值得看:曲线的峰 1.6436 比 那个点本身的 1.9 要低——加权均值总会把尖峰往周围「抹」平一点;两端( 和 )的预测 0.5190、−0.0900 都被往数据内侧「拉」——边缘处只有一侧有数据,另一侧没有邻居来平衡。δ=3.0 那列就平得多:峰谷差从 1.73 压到 0.53,整条曲线几乎被熨平、贴着全局均值 0.84 附近——δ 就是这条曲线的「平滑旋钮」。
带子与 δ:这条线还自带「置信区域」
别忘了,我们求的是加权的均值——均值的「概率最大」落在这条中心线上,越往边缘概率越小,像一个分布一样。讲师的图景是:中心这条线是最大值,像一条带子一样过来——横过来看,每个点上都有一个近似高斯的函数:以这条线为最大值,往左往右不同位置有不同概率的分布。
所以给定这些点,可以画出一个区域——这个区域是这些点的估计值所在的范围,而且是有 confidence level(置信水平)的。想知道 90% 的区域存在于什么地方,就根据 δ 的值来选定这个带子的宽度,整个区域的估计就都出来了——可以直接估计给定任何 值所对应的 的分布。
(一个诚实框:δ 是核的宽窄参数,置信水平是另一件事——讲师口播「把 delta 调成 90%」是松散的说法。准确的关系是:δ 决定每个点上那个「近似高斯」的胖瘦,从而决定带子的宽窄;想要严格对应某个置信水平的带,要按那个分布的分位数去画。直觉上「δ 越大带越宽」是对的。)
到这里收尾。这个模型就是一个 nonparametric model——都是由数据自己本身来进行说话的:data talk for themselves,它自己给自己说话。我们并没有假设这条线是正态、是线性或是什么其他情况;完全根据给定的 kernel 的定义,找到拟合数据最好的、概率最大的这条线。
📝 动手练一练
- 「k 之问」:KNN 需要指定 k,为什么它仍然是「无参模型」?请用一句话说出有参模型与无参模型在「参数从哪来」上的本质区别,并再举一个本课学过的无参模型(提示:第十六、十七章里找)。
👉 点击查看参考答案
关键在判别靠什么:KNN 判别一个点属于哪类,靠的是它周围邻居数据的投票,而不是 k——k 是开工前定好的「规则」,我们从不用训练数据去「训练」k。有参模型的参数(如线性模型的 θ、正态分布的 μ 和 σ)是从数据里学出来的;无参模型要学的「东西」就是数据本身。本课学过的其他无参模型:第十六、十七章的降维方法(如 Isomap 找近邻、LLE 保留局部重构关系)很多都属于无参模型——它们都没有一个要训练的参数化函数形式。
- Nadaraya-Watson 手算:数据 ,查询点 ,高斯核 。请手算三个点的权重、以及 的预测值;再对比「k=1 最近邻」会给出什么,说说两者的差别。
👉 点击查看参考答案
权重 : 距离 0,权重 ; 和 距离都是 1,权重 。
预测约 0.83。k=1 最近邻则直接抄最近点的 ——一步跳变、不平滑;而 Nadaraya-Watson 让左右两个邻居也按权重参与(1.5 那个点把预测往上拽,0.2 那个往下拽),得到的是平滑过渡的估计——正是「从邻域跳变到全局加权」的意义。
本章小结
这一节从课程大地图出发(度量学习、迁移学习、深度学习、强化学习、遗传编程、meta learning 都是没来得及展开的板块,本课的定位是 introduction to machine learning),然后正式进入无参模型。第一,有参模型统一回顾:线性模型、概率模型(μ、σ)、生成模型(HMM 的释放矩阵与转移矩阵)都是「先定形式、再学参数」;第二,无参的定义与「k 之问」:KNN 的关键是邻居数据而非 k,我们不「训练」k;第三,三步泛化:邻域均值 → 邻域加权(谁近谁权大)→ 全局加权,权重由核函数 给出(自身处最大、无穷远处趋零);第四,核密度估计:每个数据点放一个固定小方差的小高斯,累加、归一化(数值积分验证 = 1.0000),不假设整体分布,小高斯的作用是平滑数据之间的噪音;第五,Nadaraya-Watson 核回归:分子加权、分母归一化, 从 扫到 学出一条逼近连续的拟合曲线,δ 是平滑旋钮,还自带一条与 δ 相关的置信带子。一句话收官:data talk for themselves——数据自己给自己说话。
📋 行动清单
- 口述「k 之问」:不借助资料,向同学解释清楚「KNN 有 k 却是无参模型」的完整推理。
- 跑改代码:把 NW 扫描块的 δ 改成 0.5 和 2.0 各跑一遍,观察曲线峰谷差的变化方向。
- 手算一遍:独立完成练一练第 2 题的 Nadaraya-Watson 手算,再与代码结果对账。
- 建立连接:用自己的话说清「KNN → 邻域加权 → 全局加权」三步泛化,跟「Isomap → LLE → SNE」的思想深化路线有什么共同点。
—— 小象教研组
配套资料 · 直接下载
课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。
- 下载第18章笔记:核方法(Kernel)