想象你要为一座城市设计旅游手册。城市太大,你不可能把每条街巷都写进去,于是你派出游客,让他们按自己的兴趣在街区里穿行,记录走过的路线。有人喜欢在熟悉的小巷反复转悠,有人喜欢顺着大道一路奔向远方。把这些路线汇总起来,你就能摸清每个街区“到底和谁关系亲近”。这就是 Node2Vec 的世界:把图里的节点当作街区,用带偏好的随机游走采集路线,再让模型从路线中学会每个节点的向量画像。游客的偏好由两个旋钮控制——p 和 q,一个决定“恋旧程度”,一个决定“冒险程度”,二者共同决定了游走是偏向在附近打转,还是奔向远方。
对 AI 从业者来说,Node2Vec 是图表示学习的基石,也是理解 GNN 前必备的思维模型。掌握了它的随机游走策略,你就懂得如何把网络结构变成可计算的向量,进而解决推荐、风控、知识图谱等真实问题。
目录
可视化演示
展示决策树构建中的信息熵计算、信息增益比较和最优分裂选择过程,动态演示ID3算法的核心决策逻辑。
本节配有交互动效(进入视口后自动加载,约 3KB)。
信息熵计算 信息熵衡量数据集的不确定性,值越大纯度越低 公式:H(D) = -Σ pᵢ log₂ pᵢ,pᵢ为第i类样本占比 H(D) = -Σ pᵢ log₂ pᵢ
1. 图嵌入动机:把街区浓缩成一张名片
你是城市规划师,要给整座城市做旅游手册。街区太多,不能把每一条街道都写进去,你只能把每个街区浓缩成一张名片:位置、氛围、人气、和谁相邻。图嵌入也想做同样的事——把图中每个节点压缩成一串数字向量,让这串数字尽可能表达它在网络里的“社交位置”。
传统做法给节点做 one-hot 编号,就像给街区贴一个孤立序号,看不出街区之间的任何关系。图嵌入追求的是“向量距离近,节点关系近”。这样,分类、聚类、推荐等下游任务就能直接吃这些向量,而不必手工设计复杂特征。
技术上,Node2Vec 先定义了一个从节点到向量的映射函数,把节点投影到低维空间:
一张名片虽小,却能浓缩街区的“人脉圈”,这也是图嵌入的意义:牺牲细节,换回可以被计算的结构信息。
- 节点集合 V$V$ 表示图中所有节点,相当于城市里的全部街区。
- 映射函数 Φ$\Phi$ 是名片生成器,把每个节点变成一个向量。
- 目标空间 R^d$\mathbb{R}^d$ 是 d 维实数空间,向量就住在这里。
2. 随机游走基础:用游客脚印收集城市故事
名片不能凭空捏造,需要素材。于是你派出许多游客,让他们在城市里随机穿行,每走一步就记下一个节点。这些脚印连起来,就形成一条“节点序列”,如同自然语言处理里的句子,节点是词,序列是句子。
有了句子,就能借用 Word2Vec 的思路:用滑动窗口截取“上下文”,让出现在同一窗口里的节点互相学习。若两个节点经常被同一条游走路线带到一起,它们的向量就会变得相似。
一条随机游走序列可以写成:
游客脚印越丰富,模型看到的“句子”就越多,学出的街区名片也越准确。
- 游走序列 W$W$ 是一条完整的随机游走记录,相当于游客的城市旅行日记。
- 每一步节点 w_i$w_i$ 表示第 i 步踩到的节点,是日记里的一个地名。
- 游走总长度 T+1$T+1$ 是序列长度,也就是游客总共走过的节点数。
3. 二阶马尔可夫:记住来路才有方向感
如果游客每到一个岔路口都完全失忆,只凭当前街区做决定,那么路线会非常混乱。现实中有方向感的游客会回头看看:我从哪条街来的?上一条街和我当前位置的关系是什么?Node2Vec 也引入了这份“来路记忆”,让游走不仅看当前节点,还看上一跳节点。
这就是二阶马尔可夫性:决策时既考虑现在,也考虑刚刚走过的路。它帮助模型区分“折返”和“前行”,从而产生更丰富的结构信号。
下一步选择候选节点 x 的概率可以写成:
记住来路,游客才不会像无头苍蝇;这正是 Node2Vec 比朴素随机游走更“懂结构”的原因。
- 当前节点 v_{i-1}$v_{i-1}$ 是游客此刻所在的节点,相当于脚下这条街。
- 上一跳节点 v_{i-2}$v_{i-2}$ 是游客刚刚离开的节点,相当于来时的路。
- 候选节点 x$x$ 是下一个可能到达的节点,也就是前方岔路口的选项。
- 条件概率 P$P(v_i = x \mid v_{i-1}, v_{i-2})$ 代表带着来路记忆做选择。
4. p与q参数:给游客装上性格旋钮
同样是逛城市,有人喜欢在刚离开的小巷里反复折返,好像要确认每个细节;有人则喜欢大步流星冲向新的远方。Node2Vec 用两个旋钮模拟这两种性格:p 控制“回头”的冲动,q 控制“远走”的欲望。
当从前一个节点 t 走到当前节点 v,再决定下一步 x 时,算法根据 x 与 t 的距离给边权施加一个调整系数。距离为 0 表示回到 t,距离为 1 表示 x 与 t 直接相连,距离为 2 表示 x 离 t 有两跳,属于“更远的选择”。
这个调整系数写出来是:
两个旋钮一左一右,决定了游客是在熟悉的街区反复巡逻,还是沿着大道一路探索远方。
- 非归一化概率 π_vx$\pi_{vx}$ 是从当前节点 v 走向候选邻居 x 的未归一化权重,相当于岔路口的“吸引力分数”。
- 原始边权 w_vx$w_{vx}$ 是节点之间原本的连边权重,相当于道路本身的通行度。
- d=0 回到上一跳$d_{tx}=0$ 时下一步就是 t,系数是 $1/p$,p 越小越想回头。
- d=1 直接邻居$d_{tx}=1$ 时 x 与上一跳 t 直接相邻,系数是 1,保持中性。
- d=2 走得更远$d_{tx}=2$ 时 x 相对 t 更远,系数是 $1/q$,q 越小越愿意远行。
5. 归一化转移:把吸引力变成真实概率
岔路口的“吸引力分数”不能直接用。比如一个路口有五条路,吸引力分别是 2、1、1、1、1,游客并不会把 2 当成概率,而要先算总吸引力,再计算每条路所占比例。归一化就是把各项权重除以总和,让它们加在一起等于 1。
在 Node2Vec 中,非归一化概率 π 要除以当前节点所有邻居的非归一化概率之和,才能得到真正的转移概率:
只有做完归一化,游客的选择才符合概率规律,采样才不会偏向某个路口。
- 邻居集合 N(v)$N(v)$ 是当前节点 v 的所有邻居,相当于脚下路口的全部出口。
- 分子 π_vx$\pi_{vx}$ 是候选节点 x 的非归一化吸引力。
- 分母求和$\sum_{u \in N(v)} \pi_{vu}$ 是把所有邻居的吸引力加起来,得到总吸引力。
- 归一化概率 P$P(v_i = x \mid v_{i-1}=v)$ 是最终的概率,所有邻居的概率相加等于 1。
6. DeepWalk对比:从无差别乱逛到偏好漫游
在 Node2Vec 出现之前,DeepWalk 已经用随机游走做过图嵌入。但 DeepWalk 的游客没有性格:每到一个路口,所有邻居被选中的概率完全一样,只管往前走,不回头也不探险。
Node2Vec 把它升级为带偏置的游走,用 p、q 两个旋钮重新分配岔路口的吸引力。事实上,当 p=1、q=1 时,Node2Vec 就退化成 DeepWalk:
DeepWalk 像“无差别乱逛”,Node2Vec 则是“带剧本的漫游”。后者能根据任务需要捕捉局部社群或全局骨架,表达力自然更强。
- 返回参数 p=1$p=1$ 时回到上一跳的系数是 1,没有回头偏好。
- 出入参数 q=1$q=1$ 时走向更远节点的系数也是 1,没有远方偏好。
- 系数恒为 1$\alpha_{pq}(t,x)=1$ 说明每个方向的权重完全由原始边权决定。
7. 调参经验:游走次数和长度决定素材质量
拍一部城市纪录片,如果只派一个游客出门十分钟,素材肯定不够;如果派太多游客走太远,又会拍到大量重复场景。Node2Vec 的调参也类似,核心是三个量:游走次数、游走长度、窗口大小。
游走次数 r 决定总共采集多少条序列,游走长度 l 决定每条序列走多长,窗口大小 k 决定模型用多宽的上下文学习。三者共同决定了喂给 Word2Vec 的样本总规模:
实际经验中,p、q 通常设为 0.25 到 4 之间的值,r 和 l 则根据图规模调整。素材太少学不准确,素材太多训练变慢,平衡才是关键。
- 游走次数 r$r$ 是每个节点出发的游走条数,相当于派出多少批游客。
- 游走长度 l$l$ 是每条游走包含多少节点,相当于每批游客走多远。
- 总样本步数$r \times l$ 是所有游走累加的总步数,决定语料规模。
8. 评估可视化:旅行日记能否还原城市地图
训练完向量,怎么知道游客的旅行日记有没有真正抓住街区关系?一个朴素的想法是:把学到的向量拿去做相似度计算,看关系近的街区向量是否也更近。另一个思路是把向量喂给下游分类任务,看准确率如何。
最常用的相似度指标是余弦相似度——它只看两个向量的方向是否一致,不受向量长度影响:
除了相似度,还可以把向量降维后画在二维平面上,肉眼观察社区是否聚在一起。旅行日记写得越准,这座城市的社交版图就越清晰。
- 向量点积 u·v$u \cdot v$ 是两个节点向量逐位相乘后相加,衡量整体重合程度。
- 模长乘积$\|u\|\,\|v\|$ 是两个向量长度的乘积,用来消除长度差异。
- 余弦相似度$\mathrm{sim}(u,v)$ 最终给出一个 [-1,1] 之间的值,代表两个节点在嵌入空间里的亲疏。
AI 应用场景
推荐系统中的商品向量化
阶段:特征工程与数据准备
解决的问题:传统协同过滤只利用“用户-物品”共现,难以捕捉物品之间的多跳关系;Node2Vec 把用户行为序列构造成商品图,用带偏置游走生成商品序列,再学习商品向量。
具体案例:电商平台把用户点击、加购、支付行为连成商品图,每个商品是节点。利用 Node2Vec 学出商品向量后,可以计算相似商品,做“看了又看”推荐,也可以将商品向量直接作为排序模型的特征。
金融风控中的团伙识别
阶段:模型训练与图特征表示
解决的问题:欺诈团伙在资金网络中往往形成隐蔽的局部聚集结构,普通统计特征难以发现;Node2Vec 的 p/ q 参数可以分别强化局部搜索和全局探索,从而更灵活地把交易网络结构编码进节点向量。
具体案例:反欺诈团队把账户、设备、IP 地址连成异构图,用 Node2Vec 学习节点向量,再输入分类模型识别风险节点。通过调整 q 较小,游走更容易沿资金链路远行,从而发现跨多跳的团伙成员。
Python 演示
import randomfrom collections import defaultdict class BiasedRandomWalk: def __init__(self, adj_list, p, q, walk_length): self.adj_list = adj_list self.p = p self.q = q self.walk_length = walk_length def _alpha(self, prev, cur, nxt): if prev is None or nxt == prev: return 1.0 / self.p if nxt in self.adj_list[prev]: return 1.0 return 1.0 / self.q def _transition(self, prev, cur): weights = [] for nxt in self.adj_list[cur]: weights.append(self._alpha(prev, cur, nxt)) return random.choices(self.adj_list[cur], weights=weights, k=1)[0] def walk(self, start): path = [start] prev = None cur = start while len(path) < self.walk_length: nxt = self._transition(prev, cur) prev, cur = cur, nxt path.append(nxt) return path def main(): adj_list = { 0: [1, 2], 1: [0, 2, 3], 2: [0, 1, 4], 3: [1, 4, 5], 4: [2, 3, 5], 5: [3, 4], } walker = BiasedRandomWalk(adj_list, p=0.5, q=2.0, walk_length=6) for _ in range(3): print(walker.walk(0)) if __name__ == "__main__": main()
class BiasedRandomWalk:定义带偏置游走器,相当于给游客装上了 p、q 两个偏好旋钮。def _alpha(self, prev, cur, nxt):根据上一跳、当前节点和候选节点计算非归一化调整系数。return 1.0 / self.p候选点是上一跳节点时,回退系数由 p 控制。if nxt in self.adj_list[prev]:候选点与上一跳直接相连,系数保持 1。return random.choices(self.adj_list[cur], weights=weights, k=1)[0]按归一化后的权重采样下一步。walker = BiasedRandomWalk(adj_list, p=0.5, q=2.0, walk_length=6)p 小 q 大的配置让游走偏向局部区域。
常见误区
误区很多人觉得“参数越小,限制越小”,所以 p 越小,游走应该越自由、越能探索整个图。
正解p 控制的是回退到上一跳的倾向。p 越小,回到上一跳节点的概率越大,游走反而容易在局部反复打转,近似 BFS;真正让游客向外探索的是 q 小。
为何常见:因为“小”这个词容易让人联想到“更开放”,忽略了 p 和 q 在公式里的具体位置。
误区既然随机游走是采集素材,那每次游走走得越长,素材越多,效果一定越好。
正解游走长度 l 决定上下文能跨越的距离。l 过长会引入大量无关节点,增加噪声;同时还要配合窗口大小 k 使用,不是越长越优。
为何常见:人们容易把“数据量”和“数据质量”混为一谈,以为量多必然质优。
误区拿到 π 之后直接按这个值的大小当概率采样,省略归一化步骤。
正解π 只是“吸引力分数”,各项之和不为 1。必须除以当前节点所有邻居的 π 之和,得到合法概率分布后采样,否则每一步的选择都会被偏差放大。
为何常见:数学公式里先出现 π,后面才出现归一化,不少人读到一半就以为自己懂了。
误区两者都是随机游走加 Word2Vec,所以本质上没有区别,谁用都一样。
正解DeepWalk 是 p=1、q=1 的特例,所有方向一视同仁;Node2Vec 通过 p、q 灵活调节 BFS 与 DFS 倾向,能捕捉更丰富的结构模式。
为何常见:只看到“随机游走”四个字,忽略了偏置系数这个关键差异。
误区模型训练完,每个节点有了输出,就以为这个输出是分类标签,可以直接拿去评估。
正解Node2Vec 是无监督表示学习,输出是节点向量而不是标签。要得到分类结果,还需要在向量上训练分类器,或者用聚类等无监督方法进一步处理。
为何常见:很多初学者把“有输出”和“有标签”画等号,混淆了表示学习与监督分类。
面试题
Q1. Node2Vec 中参数 p 的主要作用是什么?
- A.控制返回上一节点的倾向← 正确答案
- B.控制向远处探索的倾向
- C.控制游走步长的长短
- D.控制采样的邻居数量
答案:A。p 作用于 d=0 的情况,也就是候选节点正好是上一跳节点时,非归一化概率要乘以 1/p。p 越小回退倾向越强。B 是 q 的作用,C、D 与 p 无关。
Q2. DeepWalk 可看作 Node2Vec 的哪种特例?
- A.p=1 且 q=1← 正确答案
- B.p=0 且 q=1
- C.p=1 且 q=0
- D.p=0 且 q=0
答案:A。当 p=1 且 q=1 时,回头、直行、走远的调整系数全部是 1,带偏置游走退化成均匀游走,这正是 DeepWalk。
Q3. 二阶马尔可夫随机游走中,决定下一步概率时额外使用的关键信息是?
- A.上一跳节点← 正确答案
- B.游走起始点
- C.待预测终点
- D.图中全部节点
答案:A。二阶马尔可夫意味着不仅要看当前节点,还要看上一跳节点,用这两个节点联合判断下一步。B、C、D 都不是二阶模型中额外依赖的信息。
Q4. 计算邻居转移概率时,最后一步必须做什么?
- A.开平方根
- B.做归一化← 正确答案
- C.取自然对数
- D.乘窗口大小
答案:B。非归一化概率 π 之和不是 1,必须除以当前节点所有邻居的 π 之和,才能得到真正的转移概率。开平方、取对数、乘窗口都不对。
Q5. 当 p 很小且 q 很大时,随机游走更倾向于?
- A.在局部区域反复折返← 正确答案
- B.沿一条路径快速前进
- C.随机跳到任意节点
- D.立即终止游走过程
答案:A。p 小导致回到上一跳的概率高,q 大导致走向距离上一跳两跳的节点概率低,因此游走会在局部反复折返,类似 BFS。B 需要 q 小,C、D 与参数机制不符。
Q6. 二阶随机游走中,上一跳节点 t、当前节点 v、候选节点 x 的图距离 d=2;若 p=2、q=0.5、边权 w=4,则非归一化转移概率 π 是多少?
- A.8.0← 正确答案
- B.4.0
- C.2.0
- D.0.5
答案:A。d=2 时调整系数是 1/q=2,再乘边权 w=4,得到 π=8。这是对 p/q 参数和距离公式的综合考查。
Q7. 游走次数 r 过少的主要风险是什么?
- A.采样序列多样性不足← 正确答案
- B.嵌入向量维度变低
- C.下游任务严重过拟合
- D.图中节点数量会减少
答案:A。r 决定从每个节点出发采多少条序列。r 过少时样本多样性不足,模型看不到足够丰富的结构关系。维度由 d 决定,过拟合通常与模型复杂度有关,节点数量是图本身的属性。
Q8. 以下哪些属于 Node2Vec 中可以调节的核心参数?
- A.返回参数 p← 正确答案
- B.出入参数 q← 正确答案
- C.嵌入维度 d← 正确答案
- D.损失函数类型
答案:ABC。p 控制回退倾向,q 控制远走倾向,d 控制向量维度,它们都是 Node2Vec 模型设计中的关键参数。损失函数类型一般是 Word2Vec 内部固定的选项,不属于 Node2Vec 的核心调节对象。
Q9. 以下关于 p、q 对游走影响的说法,正确的有哪些?
- A.p 小则容易回退← 正确答案
- B.q 小则偏向外出← 正确答案
- C.p 小则偏向深度探索
- D.q 小则偏向局部回退
答案:AB。p 小对应 d=0 时系数大,容易回到上一跳节点,形成局部折返;q 小对应 d=2 时系数大,更容易走向离上一跳较远的节点,形成外向探索。C、D 把 p 和 q 的作用说反了。
Q10. 与 DeepWalk 相比,Node2Vec 的主要优势有哪些?
- A.灵活调节广度深度倾向← 正确答案
- B.转移概率不再完全均匀← 正确答案
- C.无需依赖图结构
- D.无需依赖负采样
答案:AB。Node2Vec 通过 p、q 调节 BFS 与 DFS 之间的平衡,转移概率由 α 系数和边权共同决定,不再均匀。Node2Vec 仍然需要图结构和负采样,C、D 说法错误。