【Graph Embedding】node2vec:算法原理,实现和应用

article/2025/11/6 20:54:58

前面介绍过基于DFS邻域的DeepWalk和基于BFS邻域的LINE。
在这里插入图片描述

DeepWalk:算法原理,实现和应用
LINE:算法原理,实现和应用

node2vec是一种综合考虑DFS邻域和BFS邻域的graph embedding方法。简单来说,可以看作是eepwalk的一种扩展,可以看作是结合了DFS和BFS随机游走的deepwalk。

nodo2vec 算法原理

优化目标

f ( u ) f(u) f(u)是将顶点 u u u映射为embedding向量的映射函数,对于图中每个顶点 u u u,定义 N S ( u ) N_S(u) NS(u)为通过采样策略 S S S采样出的顶点 u u u的近邻顶点集合。

node2vec优化的目标是给定每个顶点条件下,令其近邻顶点出现的概率最大。

m a x f ∑ u ∈ V log ⁡ P r ( N S ( U ) ∣ f ( u ) ) max_f {\sum_{u\in V}\log{Pr(N_S(U)|f(u))}} maxfuVlogPr(NS(U)f(u))

为了将上述最优化问题可解,文章提出两个假设:

  • 条件独立性假设
    假设给定源顶点下,其近邻顶点出现的概率与近邻集合中其余顶点无关。
    P r ( N s ( u ) ∣ f ( u ) ) = ∏ n i ∈ N s ( u ) P r ( n i ∣ f ( u ) ) Pr(N_s(u)|f(u))=\prod_{n_i\in N_s(u)} Pr(n_i|f(u)) Pr(Ns(u)f(u))=niNs(u)Pr(nif(u))
  • 特征空间对称性假设
    这里是说一个顶点作为源顶点和作为近邻顶点的时候共享同一套embedding向量。(对比LINE中的2阶相似度,一个顶点作为源点和近邻点的时候是拥有不同的embedding向量的)
    在这个假设下,上述条件概率公式可表示为 P r ( n i ∣ f ( u ) ) = exp ⁡ f ( n i ) ⋅ f ( u ) ∑ v ∈ V exp ⁡ f ( v ) ⋅ f ( u ) Pr(n_i|f(u))=\frac{\exp{f(n_i)\cdot f(u)}}{\sum_{v\in V}{\exp{f(v)\cdot f(u)}}} Pr(nif(u))=vVexpf(v)f(u)expf(ni)f(u)

根据以上两个假设条件,最终的目标函数表示为
m a x f ∑ u ∈ V [ − log ⁡ Z u + ∑ n i ∈ N s ( u ) f ( n i ) ⋅ f ( u ) ] max_f{\sum_{u\in V}[-\log{Z_u}+\sum_{n_i\in N_s(u)}{f(n_i)\cdot f(u)}]} maxfuV[logZu+niNs(u)f(ni)f(u)]

由于归一化因子 Z u = ∑ n i ∈ N s ( u ) exp ⁡ ( f ( n i ) ⋅ f ( u ) ) Z_u=\sum_{n_i\in N_s(u)}{\exp(f(n_i)\cdot f(u))} Zu=niNs(u)exp(f(ni)f(u))的计算代价高,所以采用负采样技术优化。

采样策略

node2vec依然采用随机游走的方式获取顶点的近邻序列,不同的是node2vec采用的是一种有偏的随机游走。

给定当前顶点 v v v,访问下一个顶点 x x x的概率为
P ( c i = x ∣ c i − 1 = v ) = { π v x Z if  ( v , x ) ∈ E 0 otherwise P(c_i=x|c_{i-1}=v)=\left\{ \begin{aligned} \frac{\pi_ {vx}}{Z} & & \text{if }(v,x)\in E \\ 0 & & \text{otherwise} \\ \end{aligned} \right. P(ci=xci1=v)=Zπvx0if (v,x)Eotherwise
π v x \pi_{vx} πvx是顶点 v v v和顶点 x x x之间的未归一化转移概率, Z Z Z是归一化常数。

node2vec引入两个超参数 p p p q q q来控制随机游走的策略,假设当前随机游走经过边 ( t , v ) (t,v) (t,v)到达顶点 v v v
π v x = α p q ( t , x ) ⋅ w v x \pi_{vx}=\alpha_{pq}(t,x)\cdot w_{vx} πvx=αpq(t,x)wvx w v x w_{vx} wvx是顶点 v v v x x x之间的边权,

α p q ( t , x ) = { 1 p = if  d t x = 0 1 = if  d t x = 1 1 q = if  d t x = 2 \alpha_{pq}(t,x)=\left\{ \begin{aligned} \frac{1}{p} & = & \text{if }d_{tx}=0\\ 1 & = & \text{if }d_{tx}=1\\ \frac{1}{q} & = & \text{if }d_{tx}=2\\ \end{aligned} \right. αpq(t,x)=p11q1===if dtx=0if dtx=1if dtx=2
d t x d_{tx} dtx为顶点 t t t和顶点 x x x之间的最短路径距离。

下面讨论超参数 p p p q q q对游走策略的影响

  • Return parameter,p
    参数 p p p控制重复访问刚刚访问过的顶点的概率。
    注意到 p p p仅作用于 d t x = 0 d_{tx}=0 dtx=0的情况,而 d t x = 0 d_{tx}=0 dtx=0表示顶点 x x x就是访问当前顶点 v v v之前刚刚访问过的顶点。
    那么若 p p p较高,则访问刚刚访问过的顶点的概率会变低,反之变高。
  • In-out papameter,q
    q q q控制着游走是向外还是向内,若q>1,随机游走倾向于访问和 t t t接近的顶点(偏向BFS)。若 q < 1 q<1 q<1,倾向于访问远离 t t t的顶点(偏向DFS)。

下面的图描述的是当从t访问到v时,决定下一个访问顶点时每个顶点对应的 α \alpha α
在这里插入图片描述

学习算法

采样完顶点序列后,剩下的步骤就和deepwalk一样了,用word2vec去学习顶点的embedding向量。
值得注意的是node2vecWalk中不再是随机抽取邻接点,而是按概率抽取,node2vec采用了Alias算法进行顶点采样。
Alias Method:时间复杂度O(1)的离散采样方法
在这里插入图片描述

node2vec核心代码

node2vecWalk

通过上面的伪代码可以看到,node2vec和deepwalk非常类似,主要区别在于顶点序列的采样策略不同,所以这里我们主要关注node2vecWalk的实现。

由于采样时需要考虑前面2步访问过的顶点,所以当访问序列中只有1个顶点时,直接使用当前顶点和邻居顶点之间的边权作为采样依据。
当序列多余2个顶点时,使用文章提到的有偏采样。

def node2vec_walk(self, walk_length, start_node):G = self.G    alias_nodes = self.alias_nodes    alias_edges = self.alias_edgeswalk = [start_node]while len(walk) < walk_length:        cur = walk[-1]        cur_nbrs = list(G.neighbors(cur))        if len(cur_nbrs) > 0:            if len(walk) == 1:                walk.append(cur_nbrs[alias_sample(alias_nodes[cur][0], alias_nodes[cur][1])])            else:                prev = walk[-2]                edge = (prev, cur)                next_node = cur_nbrs[alias_sample(alias_edges[edge][0],alias_edges[edge][1])]                walk.append(next_node)        else:            breakreturn walk

构造采样表

preprocess_transition_probs分别生成alias_nodesalias_edgesalias_nodes存储着在每个顶点时决定下一次访问其邻接点时需要的alias表(不考虑当前顶点之前访问的顶点)。alias_edges存储着在前一个访问顶点为 t t t,当前顶点为 v v v时决定下一次访问哪个邻接点时需要的alias表。

get_alias_edge方法返回的是在上一次访问顶点 t t t,当前访问顶点为 v v v时到下一个顶点 x x x的未归一化转移概率 π v x = α p q ( t , x ) ⋅ w v x \pi_{vx}=\alpha_{pq}(t,x)\cdot w_{vx} πvx=αpq(t,x)wvx

def get_alias_edge(self, t, v):G = self.G    p = self.p    q = self.qunnormalized_probs = []    for x in G.neighbors(v):        weight = G[v][x].get('weight', 1.0)# w_vx        if x == t:# d_tx == 0            unnormalized_probs.append(weight/p)        elif G.has_edge(x, t):# d_tx == 1            unnormalized_probs.append(weight)        else:# d_tx == 2            unnormalized_probs.append(weight/q)    norm_const = sum(unnormalized_probs)    normalized_probs = [float(u_prob)/norm_const for u_prob in unnormalized_probs]return create_alias_table(normalized_probs)def preprocess_transition_probs(self):G = self.Galias_nodes = {}    for node in G.nodes():        unnormalized_probs = [G[node][nbr].get('weight', 1.0) for nbr in G.neighbors(node)]        norm_const = sum(unnormalized_probs)        normalized_probs = [float(u_prob)/norm_const for u_prob in unnormalized_probs]                 alias_nodes[node] = create_alias_table(normalized_probs)alias_edges = {}for edge in G.edges():        alias_edges[edge] = self.get_alias_edge(edge[0], edge[1])self.alias_nodes = alias_nodes    self.alias_edges = alias_edgesreturn

node2vec应用

使用node2vec在wiki数据集上进行节点分类任务和可视化任务。 wiki数据集包含 2,405 个网页和17,981条网页之间的链接关系,以及每个网页的所属类别。 通过简单的超参搜索,这里使用p=0.25,q=4的设置。

本例中的训练,评测和可视化的完整代码在下面的git仓库中,

https://github.com/shenweichen/GraphEmbedding

G = nx.read_edgelist('../data/wiki/Wiki_edgelist.txt',create_using=nx.DiGraph(),nodetype=None,data=[('weight',int)])model = Node2Vec(G,walk_length=10,num_walks=80,p=0.25,q=4,workers=1)
model.train(window_size=5,iter=3)    
embeddings = model.get_embeddings()evaluate_embeddings(embeddings)
plot_embeddings(embeddings)

分类任务

micro-F1: 0.6757
macro-F1: 0.5917

这个结果相比于DeepWalk和LINE是有提升的。

可视化

这个结果相比于DeepWalk和LINE可以看到不同类别的分布更加分散了。
在这里插入图片描述

参考资料

  • Grover A, Leskovec J. node2vec: Scalable Feature Learning for Networks[C]// Acm Sigkdd International Conference on Knowledge Discovery & Data Mining. 2016.

图算法干货汇总

我把近年来主流的图表示学习方法的paper和对应的代码实现进行了汇总整理,扫码关注公众号【浅梦的学习笔记】,后台回复【图算法】即可打包下载。

在这里插入图片描述
欢迎加入星球群,一个由1300+小伙伴共建的交流平台,专注于前沿graph embedding算法技术与实践经验的分享学习。
在这里插入图片描述


http://chatgpt.dhexx.cn/article/WSCIgaQJ.shtml

相关文章

图与推荐系统(一):Graph Embedding之node2vec (原理 + 代码实战)

文章目录 一. 介绍二. 公式三. 代码细节四. 代码 一. 介绍 node2vec是一种综合考虑DFS邻域和BFS邻域的graph embedding方法。简单来说&#xff0c;可以看作是deepwalk的一种扩展&#xff0c;是结合了DFS和BFS随机游走的deepwalk。node2vec通过调整方向的参数来控制模型更倾向B…

图神经网络之Node2Vec详解

目录 背景传统算法存在的问题算法背景动机 算法随机序列的生成Node2Vec算法算法的具体流程&#xff1a; 总结相关资料 背景 传统算法存在的问题 一些方法中所提出的特征需要依赖人手工定义&#xff0c;这需要特定领域内专业人士来完成&#xff0c;而且依靠人手工定义特征的有…

node2vec算法

图嵌入算法 一、背景1.提出2.应用3.特点 二、DeepWalkRandomWalk 三、node2vec引言node2walkskip-gram(用中心词预测周围词) 一、背景 1.提出 ①使用邻接矩阵表示网络时&#xff0c;由于矩阵中大多数元素是0&#xff0c;难以体现节点间关系&#xff0c;同时数据的稀疏性使得计…

node2vec代码实现及详细解析

目录 前言1.数据导入2.node2vecWalk2.1 归一化转移概率2.1.1 原理解析2.1.2 Alias采样2.1.3 代码实现 2.2 node2vecWalk的实现 3.LearnFeatures4.参数选择5.完整代码 前言 在KDD 2016 | node2vec&#xff1a;Scalable Feature Learning for Networks 中我们详细讨论了node2vec…

Node2vec原理剖析,代码实现

DeepWalk原理介绍 与词嵌入类似&#xff0c;图嵌入基本理念是基于相邻顶点的关系&#xff0c;将目的顶点映射为稠密向量&#xff0c;以数值化的方式表达图中的信息&#xff0c;以便在下游任务中运用。 Word2Vec根据词与词的共现关系学习向量的表示&#xff0c;DeepWalk受其启…

Python(Pycharm)常用快捷键

1. Pycharm一键给所有代码加# CtrlA或者Ctrl/ 2. Pycharm格式化代码快捷键&#xff08;即标准化&#xff09; CtrlAltL 【注】qq也可能有此快捷键&#xff0c;把qq删掉就行 其实改掉Pycharm的里面的设置也可以&#xff08;这样就不会冲突了&#xff09; add keyboard shor…

python 中常见的快捷方式

相信大家在写代码的时候经常会用到快捷键&#xff0c;这不仅使编写代码的效率提高不少&#xff0c;还能装 X...下面整理了部分常见快捷键&#xff0c;后期会接着更新。废话不多说&#xff1a; 1.ctrlshiftA:万能命令行 可以新建一个python文件 2. shift两次:查看资源文件 3…

python的快捷键总结

电脑是解决众多问题的工具&#xff0c;尤其对于程序员而言&#xff0c;拥有一套快捷方式&#xff0c;在编程时&#xff0c;可以事半功倍&#xff0c;从而高效地完成工作任务&#xff0c;今天就带来一套快捷方式&#xff0c;仅供大家参考&#xff1a; 常见快捷方式&#xff1a; …

Python快捷键

1.注释(添加/消除)(Ctrl /) 这里说下Python的单行注释是 # , 多行注释是 注释内容 , java的单行注释是 // , 多行注释 /* 注释内容 */, 文档注释 /** 注释内容 */ 这里说的注释快捷键主要用于多行注释, 当你想把一段代码暂时注释掉的时候, 可以直接选中这段代码, 利用此快…

python 常用快捷键和设置

pycharm常用快捷键 转载自 大哥 1、编辑&#xff08;Editing&#xff09; Ctrl Space 基本的代码完成&#xff08;类、方法、属性&#xff09; Ctrl Alt Space 快速导入任意类 Ctrl Shift Enter 语句完成 Ctrl P 参数信息&#xff08;在方法中调用参数&#…

Python常用快捷键整理

Python常用快捷键整理 文章目录 Python常用快捷键整理一、注释二、删除三、格式四、 查看其它1. 代码自动整理 本文列举了常用的快捷键&#xff0c;暂时刚入门&#xff0c;还没有写太多&#xff0c;如有不足之处还请多多指教。 一、注释 行注释/取消行注释: Ctrl / 多行注释&…

python常用快捷键

一、编辑&#xff08;Editing&#xff09; Ctrl Space 基本的代码完成&#xff08;类、方法、属性&#xff09; Ctrl Alt Space 快速导入任意类 Ctrl Shift Enter 语句完成 Ctrl P 参数信息&#xff08;在方法中调用参数&#xff09; Ctrl Q 快速查看文档 F1 外部文档 S…

python常用快捷键,写代码事半功倍

今天就为大家带来一篇Python常用快捷键。觉得挺不错的&#xff0c;现在就分享给大家&#xff0c;也给大家做个参考。 最重要的快捷键 ctrlshiftA:万能命令行shift两次:查看资源文件 新建工程第一步操作 module设置把空包分层去掉,compact empty middle package设置当前的工…

OSGB数据的纹理压缩

运行环境 OSG3.4.1 VS2017 对osgb数据的压缩关键在于纹理的压缩&#xff0c;即可在writeNodeFIie方法中进行操作。 osgDB::writeNodeFile(*rootNode, f_path, new osgDB::Options("WriteImageHintIncludeFile"));osg老版本中的 writeImageHintIncludeFile 有缺陷(…

unity 加载倾斜摄影-C#解析osgb(一)

下载 https://download.csdn.net/download/WantFK/87009338https://download.csdn.net/download/WantFK/87009338 1.提取osgb的图片信息\mesh顶点 \UV\ 三角序列\下一级name\bounds\视距 和保存 &#xff08;提取 目的 解析osgb的流程过于麻烦 真正用地到的就这几个数据 2.un…

osg加载osgb数据_PCM点云数据处理软件功能使用第十六弹

好久不见!今日为大家带来PCM点云数据处理软件功能使用第十六弹——建筑物应用,快跟小编一起学习吧! 该菜单包含两个建筑物应用模块:建筑点云提取、建筑简易模型一 建筑点云提取 建筑物点云提取输入数据为原始点云文件和地面文件,利用法向量对非地面点进行建筑物墙面点云检…

UE加载osgb倾斜摄影数据

1.支持加载大疆智图和CC导出的osgb格式倾斜摄影数据 2.支持编辑器模式&#xff08;不运行&#xff09;加载预览特定精度级别的osgb数据 3.运行时多线程加载osgb文件&#xff0c;分页LOD算法动态加载卸载&#xff0c;内存占用稳定 4.支持海量的osgb数据量加载&#xff0c;支持…

Osgb转3DTiles工具

三维倾斜摄影生产主要格式为Osgb&#xff0c;目前三维模型主要展示场景为web&#xff0c;大部分使用框架都是Cesium库&#xff0c;格式为 3DTiles&#xff0c;目前市面上osgb转3DTiles的软件已经有好几个&#xff0c;付费免费都有。 先说免费软件&#xff1a; 1、CesiumLab …

osgb倾斜模型顶层合并

经过多年的发展&#xff0c;倾斜摄影模型技术已经成熟&#xff0c;在智慧城市、社区管理&#xff0c;安防演练模拟等应用场合非常多&#xff0c;效果也非常好。 倾斜模型顶层合并是一个比较复杂的问题&#xff0c;常规上倾斜模型制作软件&#xff0c;倾斜模型24级别合并到12级…

Threejs加载倾斜摄影OSGB数据

个人主页&#xff1a; 左本Web3D&#xff0c;更多案例预览请点击》 在线案例 个人简介&#xff1a;专注Web3D使用ThreeJS实现3D效果技巧和学习案例 &#x1f495; &#x1f495;积跬步以至千里&#xff0c;致敬每个爱学习的你。获取模型或源码请点赞收藏加留言&#xff0c;有问…