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. Mysql实现主从同步

    根据网上众多参考案例,继续在VM虚拟机里实现MySQL主从同步功能.步骤如下: * 首先明确下环境 主库本地windows ip192.168.0.103 从库虚拟机mysql5.6 ip192.16 ...

  2. Oracle 实例管理

    理解初始化参数文件实例由内存中构建它的参数来定义.许多参数(但不是全部)可以在启动后更改.有些参数在启动时就固定了,只能在关闭实例并再次启动时更改. 静态和动态参数文件参数文件由两类:静态参数文件(也 ...

  3. mac终端输入python默认打开python3

    *** 1. 终端打开.bash_profile文件 ***open ~/.bash_profile *** 2. .bash_profile文件内容 ***# Setting PATH for Py ...

  4. 网页静态化解决方案-Freemarker

    1.1    技术简介与使用 1.1.1     简介 为什么使用: 1.  减轻数据库的访问压力,静态化比较适合大规模且相对变化不太频繁的数据: 2.  有利于SEO(搜索引擎优化); 纯的HTML ...

  5. LVS负载均衡机制之LVS-DR模式工作原理以及简单配置

    本博文主要简单介绍一下LVS负载均衡集群的一个基本负载均衡机制:LVS-DR:如有汇总不当之处,请各位在评论中多多指出. LVS-DR原理: LVS的英文全称是Linux Virtual Server ...

  6. MySQL----MySQL数据库入门----第一章 数据库入门

    第一章 数据库入门 1.1 数据库基础知识 1.1.1 数据库概述 数据不仅包括普通意义上的数字,还包括文字.图像.声音等.也就是说,凡是在计算机中用来描述事物的记录都可称作数据. 数据库的基本特点: ...

  7. 偏前端-HTML5 sessionStorage-会话存储

    sessionStorage 是HTML5新增的一个会话存储对象,用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据.本篇主要介绍 sessionStorage(会话存储) ...

  8. u-boot-1.1.6第1阶段分析之make smdk2410_config指令

    uboot源码中的README文档中介绍要使用uboot必须先进行配置后编译,即先执行make xxx_config命令,然后执行make命令,下面以make smdk2410_config指令为例来 ...

  9. 20155321 2016-2017-2《Java程序设计》课堂实践项目2

    20155321 2016-2017-2<Java程序设计>课堂实践项目2 实践内容 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能,要求MyCP支持两个参数: ...

  10. 2016-2017-2 20155331 实验二《Java面向对象程序设计》实验报告

    2016-2017-2 20155331 实验二<Java面向对象程序设计>实验报告 实验内容 1.初步掌握单元测试和TDD 2.理解并掌握面向对象三要素:封装.继承.多态 3.初步掌握U ...