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 代码分析的更多相关文章

  1. Android代码分析工具lint学习

    1 lint简介 1.1 概述 lint是随Android SDK自带的一个静态代码分析工具.它用来对Android工程的源文件进行检查,找出在正确性.安全.性能.可使用性.可访问性及国际化等方面可能 ...

  2. pmd静态代码分析

    在正式进入测试之前,进行一定的静态代码分析及code review对代码质量及系统提高是有帮助的,以上为数据证明 Pmd 它是一个基于静态规则集的Java源码分析器,它可以识别出潜在的如下问题:– 可 ...

  3. [Asp.net 5] DependencyInjection项目代码分析-目录

    微软DI文章系列如下所示: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [ ...

  4. [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(5)(IEnumerable<>补充)

    Asp.net 5的依赖注入注入系列可以参考链接: [Asp.net 5] DependencyInjection项目代码分析-目录 我们在之前讲微软的实现时,对于OpenIEnumerableSer ...

  5. 完整全面的Java资源库(包括构建、操作、代码分析、编译器、数据库、社区等等)

    构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化 ...

  6. STM32启动代码分析 IAR 比较好

    stm32启动代码分析 (2012-06-12 09:43:31) 转载▼     最近开始使用ST的stm32w108芯片(也是一款zigbee芯片).开始看他的启动代码看的晕晕呼呼呼的. 还好在c ...

  7. 常用 Java 静态代码分析工具的分析与比较

    常用 Java 静态代码分析工具的分析与比较 简介: 本文首先介绍了静态代码分析的基 本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBu ...

  8. SonarQube-5.6.3 代码分析平台搭建使用

    python代码分析 官网主页: http://docs.sonarqube.org/display/PLUG/Python+Plugin Windows下安装使用: 快速使用: 1.下载jdk ht ...

  9. angular代码分析之异常日志设计

    angular代码分析之异常日志设计 错误异常是面向对象开发中的记录提示程序执行问题的一种重要机制,在程序执行发生问题的条件下,异常会在中断程序执行,同时会沿着代码的执行路径一步一步的向上抛出异常,最 ...

随机推荐

  1. 使用yum命令时提示:Another app is currently holding the yum lock

    yum正在使用,用kill命令杀死进程就可以了. 1.查看yum使用进程号 ps aux|grep yum 2.杀死进程 kill -9 进程号

  2. 微服务前端开发框架React-Admin

    前言 React-Admin是基于React16.x.Ant Design3.x的管理系统架构. 采用前后端分离,内置了许多管理系统常用功能,通过一些脚本.封装帮助开发人员快速开发管理系统,集中精力处 ...

  3. 在金融服务计算中,必须要使用BigDecimal

    在Java程序开发过程中,比较初级(工作经验受限)的开发人员,把注意力全部放在了一些高大上的新技术中,往往忽略了一些初级问题.. 金融服务系统中,对金额的敏感至关重要,账户余额.还款金额.代收本金.代 ...

  4. SQLSERVER 使用 ROLLUP 汇总数据,实现分组统计,总计(合计),小计

    版权声明:本文为博主原创文章,未经博主允许不得转载.本人观点或有不当之处,请在评论中及时指正,我会在第一时间内修改. https://blog.csdn.net/aiming66/article/de ...

  5. Ubuntu下配置MySql

    安装mysql sudo apt-get install mysql-server 检查安装是否成功 sudo netstat -tap | grep mysql 登录mysql mysql -uro ...

  6. 什么是ajax和json,说说他们的优缺点

    ajax异步传输的js和xml.实现页面无刷新状态更新页面和异步提交 所谓异步,简单解释就是:向服务器发送请求的时候,我们不必等待结果,而是同时做其他的事情,等到有了结果后它自己会根据设定进行后续操作 ...

  7. 一位老手关于HTML5的见解

    HTML5新特性总结  HTML5属于上一代HTML的新迭代语言,设计HTML5最主要的目的是为了在移动设备上支持多媒体!!!例如: video 标签和 audio 及 canvas 标记   HTM ...

  8. Delphi 的TStringBuilder防止服务器内存碎片化

    Delphi 2009+ 的 System.SysUtils提供了一个类似.Net的StringBuilder,用于存储字符数组. 很多人不明白为什么要用TStringBuilder, Delphi中 ...

  9. 利用谷歌插件破解今日头条的新闻ajax参数加密,新手都能懂

    最近在学习谷歌插件,想找个项目练练手,就拿今日头条开刀 首先访问地址是:https://www.toutiao.com/c/user/50025817786/#mid=50044041847 通过抓包 ...

  10. x01.os.24: 来点代码

    <Orange'S 一个操作系统的实现>源代码 <Linux 0.11 内核完全注释>源代码 linux-0.12 源代码:  解决了 Not Owner 问题 闲来无事,在 ...