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代码分析之异常日志设计 错误异常是面向对象开发中的记录提示程序执行问题的一种重要机制,在程序执行发生问题的条件下,异常会在中断程序执行,同时会沿着代码的执行路径一步一步的向上抛出异常,最 ...
随机推荐
- C语言入门编程思维引导
编程思维引导: C语言中 include<stdio.h> 称之为导包,导入写好的函数库,多个则依次写 #define N 3 意思是将N这个字母定义为数字3 当使用的时候就直接用 i ...
- OpenID Connect Core 1.0(四)使用授权码流验证(上)
3.1 使用授权码流验证(Authentication using the Authorization Code Flow) 本节描述如何使用授权码流执行验证.当使用授权码流时,会从令牌终结点返回的所 ...
- js随笔--关于数组
1.split()将一个字符串分割成字符串数组 stringObject.split(separator,howmany) separator:必需,字符串或正则表达式,从该参数指定的地方分割stri ...
- 1015 德才论(sort、结构体vector)
题目: 宋代史学家司马光在<资治通鉴>中有一段著名的“德才论”:“是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德谓之小人.凡取人之术,苟不得圣人,君子而与之,与其得小人,不 ...
- 在软件webstorm中给img标签加入class报错显示错误selector matches unknow element
如题,怎么也搞不懂,在其他软件没出过这种问题,偏偏在webstorm中,显示class选择器未匹配到元素:哪位大神知道怎么解决这个问题.
- 解决在 win10 下 vs2017 中创建 MFC 程序拖放文件接收不到 WM_DROPFILES 消息问题
解决方案 这个问题是由于 win10 的安全机制搞的鬼,即使以管理员权限运行也不行,因为它会把 WM_DROPFILES 消息过滤掉,那怎么办呢?只需在窗口初始化 OnInitDialog() 里添加 ...
- C语言 经典编程100
一.题目 [程序1] 题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 1.程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所有的排列后再去掉不满足条件 ...
- vue中组件间的传参
1.父传子 父组件准备一个数据,通过自定义属性给子组件赋值,进行传递 在子组件中通过 props 属性来接收参数 <body> <div id="app"> ...
- 20155315实验三 敏捷开发与XP实践
实验内容 1.XP基础 2.XP核心实践 3.相关工具 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器> 课程: 2.完成实验.撰 ...
- # C语言假期学习笔记——6
C语言假期学习笔记--6 数组 主要学习了一位数组和二维数组. 数组是一组具有相同类型的变量的集合.C语言程序通过元素的下标来访问数组中的元素.(下标从0开始) 一位数组 类型 数组名[元素个数] 二 ...