查看全课大纲(第 71 / 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 回传
局部线性嵌入
约 40 分钟
小象实战讲义 · 机器学习算法精讲
上一章末尾讲 LLE 时说过:核心思路好懂,但每个公式的具体推导「需要下节课再跟进」——这节课就来兑现这句话。我们把 LLE(Local Linear Embedding,局部线性嵌入)的两步数学完整推一遍:第一步在高维空间里学「每个点由邻居线性重构」的权重 ,第二步带着这份 去低维空间里找一组坐标 ——最后你会发现,兜兜转转,落脚点又是我们的老朋友:特征值与特征向量。
💡 核心导读
- 嵌入(embedding):把不容易直接表示的量(词、图、情感、句子……)变成空间里的一个向量——机器学习里特别常用的说法;LLE 是它在降维领域的一个具体实现。
- LLE 的核心假设:高维空间里每个点,都可以由它最近的 个邻居线性组合出来——「我是谁,由我身边的朋友定义」。
- 两步走:第一步对每个点求重构权重 (带约束的优化,拉格朗日乘子出场);第二步固定 、求低维坐标 (同样带约束,同样拉格朗日)。
- 落脚点是特征分解:第二步化成 的形式——,取最小的非零特征值对应的特征向量做嵌入(丢弃的那个零特征值,恰好就是平移方向)。
- 一个容易混的点:LLE 名字里的 Linear 指局部线性重构,不是说整体映射是「乘一个矩阵」的线性降维—— 不是拿 乘出来的。
嵌入:把不容易表示的东西变成向量
先说名字。embedding 中文一般叫嵌入。大家学到深度学习的时候会碰到 Google 的 word2vec:把任何一个词映射成一个向量,中文叫词嵌入。后来你会发现有各种各样的嵌入办法——所谓的嵌入,就是把一些不太容易表示的量,变成空间里的一个向量。图可以嵌入、词可以嵌入、情感可以嵌入、句子也可以嵌入——讲师的原话是「embedding everything, everything can be embedded」。在机器学习里边,「嵌入」这个说法特别常用。
我们这里讲的是 Local Linear Embedding:通过局部线性重构的方式,在低维空间里重新安放数据,来满足它们在高维空间里的特性。
LLE 的直观:我是谁,由我的邻居定义
在高维空间 里有很多数据。挑出我们需要研究的一个点 (讲师板书上的红点):我们认为这个红点可以表示成它周围几个最近邻的线性组合。周围那几个点(板书上的绿点)是 ,每个绿点连向红点的那条线,就带一个权重 :
我们希望「 减去它的重构」的平方最小,而权重满足一个条件:周围这 个点的权重加和等于 1。
讲师给了一个好玩的类比。我是一个陌生人,我想知道我的数学成绩是多少——很惊奇的是,我可以去找我最好的几个朋友:我经常跟谁在一起玩,就把他们的数学成绩做一个加权平均,那就是我的数学成绩。因为我们相信「人以类聚,物以群分」:学习好的跟学习好的小朋友在一起,学习差的跟学习差的在一起(当然这不绝对,就是个好玩的例子)。这样即使我并不知道你的数学成绩,也可以通过你经常一起玩的小朋友的数学成绩线性组合出来。这个线性组合的 怎么组合?——这正是我们要学习的部分:它就是我们的参数、我们的权重。
再往降维的方向问一句。刚才研究的也许不是数学成绩一门,而是数理化三门成绩——那是一个三维的表示;映射到一个低维空间,可能就变成了理科平均成绩(一维)。那我们想知道:一个人的理科平均成绩,和他周围最好小伙伴的理科平均成绩之间,还是同样的线性组合关系吗?如果希望这个关系在低维空间里也保持,低维的表示 应该怎么取?——「直观上我们会问:是不是像 PCA 那样, 乘上一个矩阵 就映射到 空间了?」推导到最后你会发现,答案比「乘一个矩阵」更精巧: 直接取自一个矩阵的特征向量——这也正是 LLE 属于非线性方法的地方。下面就把这套数学完整推出来。
第一步:求重构权重
从 到矩阵形式
先定义每个点的误差 。给定 ( 从 1 到 ,共 个数据),它需要对周围的几个点构造出来——周围那几个最近邻是 ,对应的权重是 。我们要最小化的目标(对 从 1 到 加和):
推导的第一个小技巧,是把 自己「塞进」加和里。看这个变形(讲师现场一步步带大家验证过相等):
第一步成立是因为 ,所以 。于是误差改写为 ——把 从中间「挖」了出来,剩下的是 与每个邻居的差值向量。
把 个差值向量按列排成矩阵 (每列是 ,),权重排成向量 ,则 。注意 里边的 本身也是 (周围的数据点),所以这一步只是换个写法。目标变成:
这里 是全 1 列向量()—— 就是 。(讲师口播时把它说成「单位阵」,按写法是全 1 向量;「每一行加和为 1」和「」是同一件事的两种说法。)
拉格朗日乘子:老朋友又出场了
这是一个有约束的优化问题——大家应该已经很熟悉了:用拉格朗日乘子。构造拉格朗日函数(把约束改写成 ):
讲师在这里专门回扣了一句:「如果忘了,可以去看 SVM 前面那部分的 note 和课程——我花了几乎一节课去讲拉格朗日乘子、讲有条件优化」(对应本课第 10 章的拉格朗日乘子法三节:无约束到等式约束、平行条件、KKT)。
对 求导并令其为零。这里讲师停下来讲了一个很多人不清楚的细节——向量求导:一个数对一个向量求导,相当于这个数对向量的每一个分量分别求导,所以结果还是一个向量。 是 维的( 到 ,对应周围最近的 个点),于是:
对 求导则原样回收约束 ,没有新信息。
归一化收尾: 自己约掉了
代入约束 可解出 ;但更省事的做法是直接「先解再归一」: 反正正比于 ,比例常数是多少不影响「加和为 1」——那就把每个分量算出来之后,底下做个 normalization(除以总和)就完了。讲师给中间那个矩阵起了个名字:(;它正是那 个差值向量的局部 Gram 矩阵, 的口径就是协方差矩阵)。于是:
(讲师现场命名 时绕了一下——先说成「 的负一次幂叫 」、后又写 ,按最终用法, 就是 本身,权重用 。)注意 固定了,找最近邻是确定的, 固定, 就完全确定——通过 的关系,就可以找到 的关系,整个链条是干净的线性代数。
用代码把这一步真正算一遍。讲义设定:平面上三个点,用两个邻居 、 重构 (刻意让 不在两邻居的连线上):
import math
eta1 = (0.0, 0.0)
eta2 = (4.0, 0.0)
x0 = (1.0, 0.5) # 讲义设定: 待重构的点, 不在两邻居连线上
Z = [[x0[d] - eta1[d] for d in range(2)],
[x0[d] - eta2[d] for d in range(2)]] # 每行一个差值向量 z_j
Q = [[sum(Z[r][d] * Z[c][d] for d in range(2)) for c in range(2)] for r in range(2)]
det = Q[0][0] * Q[1][1] - Q[0][1] * Q[1][0]
u = [(Q[1][1] - Q[0][1]) / det, (Q[0][0] - Q[1][0]) / det] # u = Q^{-1} 1
w = [ui / sum(u) for ui in u]
print("差值向量 z1, z2 =", Z)
print("局部 Gram 矩阵 Q =", [[round(v, 4) for v in row] for row in Q])
print("归一化前 u = Q^{-1} 1 =", [round(ui, 4) for ui in u])
print("重构权重 w =", [round(wi, 4) for wi in w], " 和 =", round(sum(w), 4))
recon = [w[0] * eta1[d] + w[1] * eta2[d] for d in range(2)]
print("重构点 =", [round(v, 4) for v in recon], " 重构误差 =", round(math.dist(recon, x0), 4))差值向量 z1, z2 = [[1.0, 0.5], [-3.0, 0.5]]
局部 Gram 矩阵 Q = [[1.25, -2.75], [-2.75, 9.25]]
归一化前 u = Q^{-1} 1 = [3.0, 1.0]
重构权重 w = [0.75, 0.25] 和 = 1.0
重构点 = [1.0, 0.0] 重构误差 = 0.5三个看点:权重是 ——离谁近,谁的权重就大( 的投影离 近, 分到 0.75);权重加和恰好 1.0;重构点落在 ——正是 在「邻居连线」上的投影,剩余误差 0.5 是它离开那张「局部线性片」的垂直距离。约束下的最优重构,不一定是零误差——最优的权重给出的是邻居所能拼出的、离 最近的那个点。
第二步:求低维嵌入
把整个问题搬到 空间
有了每个点的权重,把高维数据映射到低维:( 远小于 ,这才起到降维的作用)。构造新空间里的误差——形式跟刚才一模一样,只是 换成了 :
就是刚才在高维空间里辛苦求出来的那份权重( 不是 的邻居时为 0);我们要找一组 ,让同样的 在低维空间里照样把每个点拼出来。
推导用跟第一步平行的「挖中间项」技巧:把 从减法中间提出来,,平方展开成转置乘积(讲师边写边说「我们刚才所做的事情是一样的」,中途还停下来重誊了一次板书)。于是整个目标写成矩阵形式,中间那坨东西单独命名——这就是 矩阵:
两个限制条件:位置可调,所以钉死
到这步还没完—— 还得加两条限制,否则解不唯一。讲师给的动机非常直观:
第一条:中心化,。 把高维数据映射到低维空间时,它的位置是可调的——映射到以 0 为中心、以 1 为中心、以 100 为中心都可以,全体的平移不影响「邻居关系」这个我们真正关心的东西。既然可调,那就干脆强制:所有 加和等于零,以零为中心排列。
第二条:单位协方差,。 让低维表示的协方差矩阵是单位阵——各维度去相关、统一尺度,不偏袒任何一个低维方向。
又是拉格朗日,又是特征分解
优化 、给定这两条限制,又可以构造拉格朗日函数了(第二个了——这门课走到这里,拉格朗日乘子几乎每一章都要出场一次)。对 求导令其为零,得到的是一个特别眼熟的形式:
( 是新的拉格朗日系数,讲师随口起名叫「缪」;左边系数、约分合并的过程跟第一步完全同款。)——这不就是特征分解吗!乘上 这个矩阵,相当于乘上一个常数:我们想求的,就是 矩阵的特征值和特征向量。
所以对 做特征分解,然后挑特征向量。这里有一个方向性的坑,值得单独点出来:讲师口播时三次说成「找最大的几个特征值、保留最大的几个特征向量」——这是说反了。我们全程都在最小化误差 (Rayleigh 商的最小化方向),标准解法是取最小的特征值;而 又恰好有一个天然的零特征值——每一行的权重加和为 1,意味着 ,也就是 :全 1 向量是零特征值的特征向量,它就是被第一条约束排除掉的平移方向。所以最终取法是:丢弃最小的零特征值,取第 2 到第 小的特征值所对应的特征向量,按行排成低维嵌入 。
用代码把这两件事一起看到:数据取半圆弧上的 9 个点(一条嵌在二维里的一维流形,正好回扣上一节「流形」),跑完整 LLE 两步——
import math
n = 9
arc = [(math.cos(math.pi * i / (n - 1)), math.sin(math.pi * i / (n - 1))) for i in range(n)]
def dist(a, b):
return math.hypot(a[0] - b[0], a[1] - b[1])
# 第一步: 每个点取 2 个最近邻, 求 w ∝ Q^{-1} 1 再归一化
W = [[0.0] * n for _ in range(n)]
for i in range(n):
order = sorted((j for j in range(n) if j != i), key=lambda j: dist(arc[i], arc[j]))
nbrs = order[:2]
Z = [[arc[i][d] - arc[j][d] for d in range(2)] for j in nbrs]
Q = [[sum(Z[r][d] * Z[c][d] for d in range(2)) for c in range(2)] for r in range(2)]
det = Q[0][0] * Q[1][1] - Q[0][1] * Q[1][0]
if abs(det) < 1e-12: # 近邻几乎共线时兜底均分
w = [0.5, 0.5]
else:
u = [(Q[1][1] - Q[0][1]) / det, (Q[0][0] - Q[1][0]) / det]
w = [ui / sum(u) for ui in u]
for idx, j in enumerate(nbrs):
W[i][j] = w[idx]
# 第二步: M = (I - W)^T (I - W)
M = [[sum(((1.0 if a == b else 0.0) - W[a][b]) * ((1.0 if a == c else 0.0) - W[a][c]) for a in range(n)) for c in range(n)] for b in range(n)]
def jacobi_eig(A, tol=1e-12, max_sweeps=100):
"""雅可比迭代: 对称矩阵特征分解, 返回(特征值, 特征向量按列)"""
n = len(A)
a = [row[:] for row in A]
V = [[1.0 if i == j else 0.0 for j in range(n)] for i in range(n)]
for _ in range(max_sweeps):
off = math.sqrt(sum(a[p][q]**2 for p in range(n) for q in range(n) if p != q))
if off < tol:
break
for p in range(n - 1):
for q in range(p + 1, n):
if abs(a[p][q]) < 1e-15:
continue
theta = 0.5 * math.atan2(2 * a[p][q], a[q][q] - a[p][p])
c, s = math.cos(theta), math.sin(theta)
for k in range(n):
akp, akq = a[k][p], a[k][q]
a[k][p] = c * akp - s * akq
a[k][q] = s * akp + c * akq
for k in range(n):
apk, aqk = a[p][k], a[q][k]
a[p][k] = c * apk - s * aqk
a[q][k] = s * apk + c * aqk
for k in range(n):
vkp, vkq = V[k][p], V[k][q]
V[k][p] = c * vkp - s * vkq
V[k][q] = s * vkp + c * vkq
return [a[i][i] for i in range(n)], V
vals, V = jacobi_eig(M)
order = sorted(range(n), key=lambda i: vals[i])
print("M 的特征值(升序):", [f"{vals[i]:.6f}" for i in order])
v0 = [V[i][order[0]] for i in range(n)]
print("最小特征值对应向量(归一化后, 应为常数=平移方向):", [round(v / max(abs(x) for x in v0), 3) for v in v0])
y = [V[i][order[1]] for i in range(n)]
print("1D 嵌入 y(最小非零特征值对应的特征向量):", [round(v, 3) for v in y])
print("弧上顺序 0..8 对应 y 是否单调:", all(y[i] < y[i+1] for i in range(n-1)))M 的特征值(升序): ['0.000000', '0.000039', '0.020896', '0.167052', '0.671359', '1.755549', '3.206505', '7.882226', '7.906106']
最小特征值对应向量(归一化后, 应为常数=平移方向): [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
1D 嵌入 y(最小非零特征值对应的特征向量): [-0.512, -0.39, -0.261, -0.13, 0.0, 0.13, 0.261, 0.39, 0.512]
弧上顺序 0..8 对应 y 是否单调: True三行输出对应三件事:最小的特征值是零(数值上 0.000000),它对应的特征向量归一化后是清一色的 1.0——正是全 1 平移方向,扔掉;最小非零特征值(0.000039,一维流形的展开模式在这个谱里能量极低)对应的特征向量,就是 9 个点的 1D 嵌入——从 -0.512 到 0.512 近似等距地单调排开:半圆弧被「拉直」成了一条线段,而且点距保持得很好。一条弯在二维里的一维流形,就这么被 LLE 展开了——这就是「保持局部线性关系」换来的全局效果。
全流程总结:两个问题,一个特征分解
最后把整件事串一遍。LLE 是一个从高维空间映射到低维空间的运算,满足的条件是:在高维空间里,每一个点由它周围的邻居线性组合构造;到了低维空间,这批点(变成 之后)仍然通过同一份 组合到一起。所以问题归结为两个:
- 怎么估计?——刚才推的:每个点找 个最近邻,解带 约束的最小化, 再归一化( 完全由数据决定)。
- 怎么映射到 ?——构造 ,对 做特征分解,取最小非零的几个特征值对应的特征向量。比如 一共是十维的,有十个特征值;保留(最小的非零的)三个特征向量,就相当于把 10 维映射到了 3 维。
还有一个容易混的点再钉一次:讲师总结时说「 映射到 是一个降维,是个线性的降维,一定是乘一个矩阵」——LLE 名字里的 Linear,指的是局部线性重构,不是全局线性映射。 的每一行是 的特征向量按点排布,不存在 这样的变换矩阵(那是 PCA 的形态);LLE 直接输出每个点的低维坐标,这正是它「非线性」的所在。
📝 动手练一练
- 概念辨析:PCA 和 LLE 都把落脚点放在「特征值与特征向量」上,但方向完全相反。请从三个方面对比两者:各自假设数据有什么样的结构?各自保留什么?解的形态差在哪(有没有 形式的映射)?
👉 点击查看参考答案
- 结构假设:PCA 假设数据整体分布在一个全局线性子空间上(16.3 节);LLE 假设数据在一张弯曲的流形上,但每个点的局部邻域近似线性(本节)。
- 保留什么:PCA 保留全局方差最大的方向(投影后散得最开);LLE 保留邻居间的重构权重关系——高维里谁由谁线性拼出来,低维里还是谁由谁拼出来。
- 解的形态:PCA 是协方差矩阵取最大特征值对应的特征向量当投影方向,映射可以写成 的显式矩阵乘法;LLE 是 取最小非零特征值对应的特征向量当坐标,没有 的形式——这也是它属于非线性降维的原因。
一个漂亮的对称:两者都要丢一个「多余」的特征方向——PCA 丢的是均值方向(中心化),LLE 丢的是全 1 向量(平移方向,)。
- 代码实验:把上面块1 代码里的 从 改成 ——跑到 的外侧去了。先猜权重会变成什么样,再跑代码验证。这说明 LLE 的权重有什么性质?
👉 点击查看参考答案
# 为保证本块可独立运行, 重写权重求解
import math
eta1 = (0.0, 0.0)
eta2 = (4.0, 0.0)
x0 = (5.0, 0.5) # 跑到 eta2 外侧
Z = [[x0[d] - eta1[d] for d in range(2)],
[x0[d] - eta2[d] for d in range(2)]]
Q = [[sum(Z[r][d] * Z[c][d] for d in range(2)) for c in range(2)] for r in range(2)]
det = Q[0][0] * Q[1][1] - Q[0][1] * Q[1][0]
u = [(Q[1][1] - Q[0][1]) / det, (Q[0][0] - Q[1][0]) / det]
w = [ui / sum(u) for ui in u]
print("差值向量 z1, z2 =", Z)
print("局部 Gram 矩阵 Q =", [[round(v, 4) for v in row] for row in Q])
print("归一化前 u = Q^{-1} 1 =", [round(ui, 4) for ui in u])
print("重构权重 w =", [round(wi, 4) for wi in w], " 和 =", round(sum(w), 4))
recon = [w[0] * eta1[d] + w[1] * eta2[d] for d in range(2)]
print("重构点 =", [round(v, 4) for v in recon], " 重构误差 =", round(math.dist(recon, x0), 4))差值向量 z1, z2 = [[5.0, 0.5], [1.0, 0.5]]
局部 Gram 矩阵 Q = [[25.25, 5.25], [5.25, 1.25]]
归一化前 u = Q^{-1} 1 = [-1.0, 5.0]
重构权重 w = [-0.25, 1.25] 和 = 1.0
重构点 = [5.0, 0.0] 重构误差 = 0.5权重变成了 :出现了负权重,而且加和仍然是 1。这说明 LLE 的「线性组合」不是凸组合——权重可以为负、可以超过 1,只要加和为 1。重构点依然是 在邻居连线上的投影(这次是延长线上的 ,误差还是 0.5)。约束 保证的是平移不变性(所有邻居一起挪,重构结果跟着挪),而不是把权重限制在 0 和 1 之间。
本章小结
这一节把 LLE 的数学完整推完了。直观:每个点由它最近的 个邻居线性重构——「我是谁,由我身边的朋友定义」;权重加和为 1,是参数、是学出来的。第一步:对每个点解带约束的最小化 ——拉格朗日乘子(第 10 章的老朋友)给出 ,归一化收尾; 完全由数据决定,链条干净。第二步:把同样的重构关系搬到低维,误差写成 ();两条限制(以零为中心、单位协方差)钉死平移和尺度自由度;再上一次拉格朗日,得到 ——特征分解。取最小非零特征值对应的特征向量(全 1 的零特征向量是平移方向,丢弃),半圆弧的实验亲眼看到:弯曲的一维流形被拉直成近似等距的线段。最后记住那个容易混的点:LLE 的 Linear 是局部线性, 不是 乘矩阵乘出来的——这正是它与 PCA 的分野。
📋 行动清单
- 复述两步:合上讲义,说出 LLE 两步各自在优化什么、约束各是什么、各自用什么数学工具解。
- 验证 :在块2 代码里加一行,直接计算 ,亲眼看到它等于零向量。
- 改近邻数:把块2 的近邻数从 2 改成 3(注意 时三个邻居的 可能接近奇异——体会讲义代码里那个兜底分支为什么存在)。
- 对照 PCA:把 16.3 节 PCA 的「取最大特征值」与本节「取最小非零特征值」放在一起,用自己的话讲清为什么方向相反。
—— 小象教研组
配套资料 · 直接下载
课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。
- 下载第17章笔记:局部线性嵌入(LLE)