Node2vec 代码分析
Node2vec 代码从Github上clone到本地,主要是main.py和node2vec.py两个文件。
下面把我的读代码注释放到上面来,
import numpy as np
import networkx as nx
import random
class Graph():
def __init__(self, nx_G, is_directed, p, q):
self.G = nx_G
self.is_directed = is_directed
self.p = p
self.q = q
def node2vec_walk(self, walk_length, start_node):
'''
Simulate a random walk starting from start node.
'''
G = self.G
alias_nodes = self.alias_nodes
alias_edges = self.alias_edges
walk = [start_node]
while len(walk) < walk_length:
cur = walk[-1]
cur_nbrs = sorted(G.neighbors(cur))
if len(cur_nbrs) > 0:
if len(walk) == 1:
walk.append(
cur_nbrs[alias_draw(alias_nodes[cur][0],
alias_nodes[cur][1])
]
"""
结合cur_nbrs = sorted(G.neighbor(cur)) 和 alias_nodes/alias_edges的序号,
才能确定节点的ID。
所以路径上的每个节点在确定下一个节点是哪个的时候,都要经过sorted(G.neighbors(cur))这一步。
"""
)
else:
prev = walk[-2]
next = cur_nbrs[
alias_draw(alias_edges[(prev, cur)][0],
alias_edges[(prev, cur)][1])
]
walk.append(next)
else:
break
return walk
def simulate_walks(self, num_walks, walk_length):
'''
Repeatedly simulate random walks from each node.
'''
G = self.G
walks = []
nodes = list(G.nodes())
print 'Walk iteration:'
for walk_iter in range(num_walks):
print str(walk_iter+1), '/', str(num_walks)
random.shuffle(nodes)
for node in nodes:
walks.append(self.node2vec_walk(walk_length=walk_length, start_node=node))
return walks
def get_alias_edge(self, src, dst):
'''
Get the alias edge setup lists for a given edge.
'''
G = self.G
p = self.p
q = self.q
unnormalized_probs = []
for dst_nbr in sorted(G.neighbors(dst)):
if dst_nbr == src:
unnormalized_probs.append(G[dst][dst_nbr]['weight']/p)
elif G.has_edge(dst_nbr, src):
unnormalized_probs.append(G[dst][dst_nbr]['weight'])
else:
unnormalized_probs.append(G[dst][dst_nbr]['weight']/q)
norm_const = sum(unnormalized_probs)
normalized_probs = [float(u_prob)/norm_const for u_prob in unnormalized_probs]
"""
对边的权重,变化后的权重,再进行归一化了。
生成的normalized_probs,是对一条边的终点的下一步节点转移的归一化概率的列表
"""
return alias_setup(normalized_probs)
"""
返回的参数,第一个返回值是别名列表,第二个返回值是到各个节点的转移概率。
"""
def preprocess_transition_probs(self):
'''
Preprocessing of transition probabilities for guiding the random walks.
'''
G = self.G
is_directed = self.is_directed
alias_nodes = {}
for node in G.nodes():
unnormalized_probs = [G[node][nbr]['weight'] for nbr in sorted(G.neighbors(node))]
"""
G.neighbors(node)得到一个邻接节点列表
这里面sorted(G.neighbors(node))的用法,非常重要
unnormailized_probs是一个列表,列表的每个元素是边上的权重
"""
norm_const = sum(unnormalized_probs)
normalized_probs = [float(u_prob)/norm_const for u_prob in unnormalized_probs]
"""
这样就得到了归一化的、到各点的转移概率
"""
alias_nodes[node] = alias_setup(normalized_probs)
"""
alias_nodes[node]是一个字典,字典的value,又是一个包含两个元素的元组(tuple): 第一个元素是别名列表,第二个元素是到各个节点的转移概率。
"""
alias_edges = {}
"""
alias_edges是字典
"""
triads = {}
if is_directed:
for edge in G.edges():
alias_edges[edge] = self.get_alias_edge(edge[0], edge[1])
else:
for edge in G.edges():
"""
在alias_edges字典中加入项
alias_edges[edge]是一个字典,字典的value,又是一个包含两个元素的元组(tuple):
第一个元素是边的终点的邻接节点转移概率对应的别名列表(sorted的前后序号,不是节点序号),第二个元素是边的终点,到各个节点的转移概率。
"""
alias_edges[edge] = self.get_alias_edge(edge[0], edge[1])
alias_edges[(edge[1], edge[0])] = self.get_alias_edge(edge[1], edge[0])
self.alias_nodes = alias_nodes
self.alias_edges = alias_edges
"""
这里面alias_nodes和alias_edges都是字典,字典的元素组成都是 '节点序号':'(邻接节点转移概率对应的别名列表(sorted的前后序号,不是节点序号), 到邻接节点的转移概率)' 的形式。
不同的是,alias_edges中,'到邻接节点的转移概率'这个取值,有p或q的影响。
"""
return
def alias_setup(probs):
'''
Compute utility lists for non-uniform sampling from discrete distributions.
Refer to https://hips.seas.harvard.edu/blog/2013/03/03/the-alias-method-efficient-sampling-with-many-discrete-outcomes/
for details
the input list probs, in this using context, is the normalized weight of nodes already sorted in ID order.
'''
K = len(probs)
q = np.zeros(K)
J = np.zeros(K, dtype=np.int)
"""
J is the alias array, recording the alias's corresponding discrete integer
"""
smaller = []
larger = []
for kk, prob in enumerate(probs):
q[kk] = K*prob
if q[kk] < 1.0:
smaller.append(kk)
else:
larger.append(kk)
while len(smaller) > 0 and len(larger) > 0:
small = smaller.pop()
large = larger.pop()
J[small] = large
q[large] = q[large] + q[small] - 1.0
if q[large] < 1.0:
smaller.append(large)
else:
larger.append(large)
"""
this part of code, needs to prove that, the alias array will eventually form and exit the loop.
however, see the code of line 147 and line 148, that makes most of the alias method outstanding strength.
"""
return J, q
def alias_draw(J, q):
'''
Draw sample from a non-uniform discrete distribution using alias sampling.
'''
K = len(J)
kk = int(np.floor(np.random.rand()*K))
if np.random.rand() < q[kk]:
return kk
else:
return J[kk]
上面的代码理解,主要是需要理解alias method在生成满足 离散随机变量 的分布律的随机值的过程中前的预处理过程alias_setup,以及生成随机值的alias_draw函数。
这其中,alias_setup的执行时间在 \(O(n\log n)\) ,alias_draw的复杂性是 \(O(1)\) 。alias_method的参考资料,在代码中指出的Sampling外,还有一篇CSDN上的博客及其英文原博客。
Node2vec 代码分析的更多相关文章
- Android代码分析工具lint学习
1 lint简介 1.1 概述 lint是随Android SDK自带的一个静态代码分析工具.它用来对Android工程的源文件进行检查,找出在正确性.安全.性能.可使用性.可访问性及国际化等方面可能 ...
- pmd静态代码分析
在正式进入测试之前,进行一定的静态代码分析及code review对代码质量及系统提高是有帮助的,以上为数据证明 Pmd 它是一个基于静态规则集的Java源码分析器,它可以识别出潜在的如下问题:– 可 ...
- [Asp.net 5] DependencyInjection项目代码分析-目录
微软DI文章系列如下所示: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [ ...
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(5)(IEnumerable<>补充)
Asp.net 5的依赖注入注入系列可以参考链接: [Asp.net 5] DependencyInjection项目代码分析-目录 我们在之前讲微软的实现时,对于OpenIEnumerableSer ...
- 完整全面的Java资源库(包括构建、操作、代码分析、编译器、数据库、社区等等)
构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化 ...
- STM32启动代码分析 IAR 比较好
stm32启动代码分析 (2012-06-12 09:43:31) 转载▼ 最近开始使用ST的stm32w108芯片(也是一款zigbee芯片).开始看他的启动代码看的晕晕呼呼呼的. 还好在c ...
- 常用 Java 静态代码分析工具的分析与比较
常用 Java 静态代码分析工具的分析与比较 简介: 本文首先介绍了静态代码分析的基 本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBu ...
- SonarQube-5.6.3 代码分析平台搭建使用
python代码分析 官网主页: http://docs.sonarqube.org/display/PLUG/Python+Plugin Windows下安装使用: 快速使用: 1.下载jdk ht ...
- angular代码分析之异常日志设计
angular代码分析之异常日志设计 错误异常是面向对象开发中的记录提示程序执行问题的一种重要机制,在程序执行发生问题的条件下,异常会在中断程序执行,同时会沿着代码的执行路径一步一步的向上抛出异常,最 ...
随机推荐
- Activiti6.0 spring5 工作流引擎 java SSM流程审批 项目框架
1.模型管理 :web在线流程设计器.预览流程xml.导出xml.部署流程 2.流程管理 :导入导出流程资源文件.查看流程图.根据流程实例反射出流程模型.激活挂起 3.运行中流程:查看流程信息.当前任 ...
- HP-Socket国产优秀socket通信组件推荐
来源:http://blog.csdn.net/clb929/article/details/51085983 * HP-Socket 官方网站:http://www.jessma.org * HP- ...
- MySQL数据库的隔离级别之可重复读为什么能够有效防止幻读现象的出现
可重复读隔离级别,不允许存在幻读,该隔离级别之所以能够有效防止幻读现象的出现,是因为可重复读这个隔离级别有用到GAP锁(间隙锁).下面我们以解析SQL语句为切入点,来解释个中原因. 前提条件:①数据库 ...
- lrzsz Linux服务器Windows互传文件工具
lrzsz是一款在linux里可代替ftp上传和下载的程序,但只限于较小的文件,如果是目录需要打包成单个文件在实现下载. 条件:需要使用SecureCRT或者Xshell等客户端工具连接Linux 下 ...
- 我们比较常见的PHP实现openSug.js参数调试
这是一款利PHP对百度搜索下拉框提示免费代码实现参数配置调试的程序源代码. 由想要对网站进行搜索下拉调试的站长朋友们进行方便.快速的效果演示,具体参考下面的PHP代码. 如何使用? 请新建一份PHP文 ...
- PHP 判断密码强度
$score = 0; if(preg_match("/[0-9]+/",$str)) { ...
- pomelo 的一些监控和维护插件(工具)
POMELO 提供了非常多的插件,可以方便我们日常对其的一些操作和开发工作,同样的我们也可以自己开发一些定制的插件让其伴随整个POMELO的生命周期运作(这里 不是要介绍如何制作POMELO插件),这 ...
- Security 安全框架1
security 过滤器链 检查请求是否有请求信息-主要校验规则 UsernamePasswordAuthenticationFilter: 处理表单登录, 请求是否带用户名密码 BasicAuthe ...
- java入门---修饰符&访问修饰符&非访问修饰符
Java语言提供了很多修饰符,主要分为以下两类: 访问修饰符 非访问修饰符 修饰符用来定义类.方法或者变量,通常放在语句的最前端.我们通过下面的例子来说明: public class ...
- C++基本概念复习
照着https://www.w3cschool.cn/cpp/,把C++的基础概念顺了一遍,虽然很久没用C++,还是整理一下. #include "stdafx.h"; #incl ...