社会网络_networkX学习(二)

复杂网络分析以及networkx学习

# 一、建立图或网络
# 1、无向图
import networkx as nx                            #导入NetworkX包,为了少打几个字母,将其重命名为nx
G = nx.Graph()                                        #建立一个空的无向图G
G.add_node(1)                                        #添加一个节点1
G.add_edge(2,3)                                     #添加一条边2-3(隐含着添加了两个节点2、3)
G.add_edge(3,2)                                     #对于无向图,边3-2与边2-3被认为是一条边
print(G.nodes())                                       #输出全部的节点: [1, 2, 3]
print(G.edges())                                       #输出全部的边:[(2, 3)]
print(G.number_of_edges())                    #输出边的数量:1
#这样就可以建立一个简单的无向图了。如果你的数据是存在文件里的,可以循环从文件中读取节点和边添加到G中。
[1, 2, 3]
[(2, 3)]
1
# 2、有向图
# 有向图的建立方式和无向图基本类似,只是在上述代码的第二行,将G = nx.Graph() 改为 
# G = nx.DiGraph() 。需要注意的是,此时再添加边3-2与边2-3,则被认为是两条不同的边
# (可以试着运行上述代码,自己查看结果)。
# 同时,有向图和无向图是可以相互转化的,分别用到Graph.to_undirected() 和
# Graph.to_directed()两个方法。
import networkx as nx                            #导入NetworkX包,为了少打几个字母,将其重命名为nx
G = nx.DiGraph()                                        #建立一个空的无向图G
G.add_node(1)                                        #添加一个节点1
G.add_edge(2,3)                                     #添加一条边2-3(隐含着添加了两个节点2、3)
G.add_edge(3,2)                                     #对于无向图,边3-2与边2-3被认为是一条边
print(G.nodes())                                       #输出全部的节点: [1, 2, 3]
print(G.edges())                                       #输出全部的边:[(2, 3)]
print(G.number_of_edges())
#转换为无向图
G1= G.to_undirected()
print(G1.nodes())                                       #输出全部的节点: [1, 2, 3]
print(G1.edges())                                       #输出全部的边:[(2, 3)]
print(G1.number_of_edges())
[1, 2, 3]
[(2, 3), (3, 2)]
2
[1, 2, 3]
[(2, 3)]
1

 

# 3、加权图(网络)
# 有向图和无向图都可以给边赋予权重,用到的方法是add_weighted_edges_from,它接受1个或多个
# 三元组[u,v,w]作为参数,其中u是起点,v是终点,w是权重。例如:
G.add_weighted_edges_from([(0,1,3.0),(1,2,7.5)])
# 添加0-1和1-2两条边,权重分别是3.0和7.5。
# 如果想读取权重,可以使用get_edge_data方法,它接受两个参数u和v,即边的起讫点。例如:
print(G.get_edge_data(0,1))                   #输出{'weight': 7.5},这是一个字典结构,可以查看python语法了解它的用法。
{'weight': 3.0}

 

# 二、调用图算法
# NetworkX提供了常用的图论经典算法,例如DFS、BFS、最短路、最小生成树、最大
# 流等等,非常丰富,如果不做复杂网络,只作图论方面的工作,
# 也可以应用NetworkX作为基本的开发包。具体的算法调用方法我就不一一介绍了,可
# 以浏览NX的在线手册http://networkx.lanl.gov/reference/algorithms.html,对每
# 一个算法都提供了详细的帮助文档和示例。下面只给出一个最短路算法的例子:

path=nx.all_pairs_shortest_path(G)     #调用多源最短路径算法,计算图G所有节点间的最短路径
# path[0][2]                              #输出节点0、2之间的最短路径序列: [0, 1, 2]
# 一、度、度分布

# NetworkX可以用来统计图中每个节点的度,并生成度分布序列。下边是一段示例代码(这段代码可以在Shell里一行一行的输入,也可以将其保存为一个以py结尾的纯文本文件后直接运行),注意看注释部分:

# import networkx as nx

# 对上述结果稍作处理,就可以在Origin等软件里绘制度分布曲线了,当然也可以用matplotlib直接作图,在上述代码后接着输入:

# import matplotlib.pyplot as plt                 #导入科学绘图的matplotlib包

 

# 二、群聚系数

# 这个在NetworkX里实现起来很简单,只需要调用方法nx.average_clustering(G) 就可以完成平均群聚系数的计算,而调用nx.clustering(G) 则可以计算各个节点的群聚系数。
nx.average_clustering(G)
nx.clustering(G)
{1: 0, 2: 0, 3: 0}
# 三、直径和平均距离

# nx.diameter(G)返回图G的直径(最长最短路径的长度),而nx.average_shortest_path_length(G)则返回图G所有节点间平均最短路径长度。
import networkx as nx
G_2 = nx.Graph()
G_2.add_edge(2,3)
G_2.add_edge(1,2)
G_2.add_edge(1,3)
nx.diameter(G_2)
nx.average_shortest_path_length(G_2)

 

1.0

 

# 四、匹配性

# 这个也比较简单,调用 nx.degree_assortativity(G) 方法可以计算一个图的度匹配性。
# nx.degree_assortativity(G_2)
degree = nx.degree_histogram(G)          #返回图中所有节点的度分布序列
x = range(len(degree))                             #生成x轴序列,从1到最大度
y = [z / float(sum(degree)) for z in degree]
#将频次转换为频率,这用到Python的一个小技巧:列表内涵,Python的确很方便:)
plt.loglog(x,y,color="blue",linewidth=2)           #在双对数坐标轴上绘制度分布曲线
plt.show()                                                          #显示图表
G = nx.random_graphs.barabasi_albert_graph(1000,3)   #生成一个n=1000,m=3的BA无标度网络
print(G.degree(0))                                   #返回某个节点的度
print(G.degree())                                     #返回所有节点的度
print(nx.degree_histogram(G))    #返回图中所有节点的度分布序列(从1至最大度的出现频次)
# 一、规则图

# 规则图差不多是最没有复杂性的一类图了,在NetworkX中,用random_graphs.random_regular_graph(d, n)方法可以生成一个含有n个节点,每个节点有d个邻居节点的规则图。下面是一段示例代码,生成了包含20个节点、每个节点有3个邻居的规则图:

import networkx as nx
import matplotlib.pyplot as plt
RG = nx.random_graphs.random_regular_graph(3,20) #生成包含20个节点、每个节点有3个邻居的规则图RG
pos = nx.spectral_layout(RG)          #定义一个布局,此处采用了spectral布局方式,后变还会介绍其它布局方式,注意图形上的区别
nx.draw(RG,pos,with_labels=False,node_size = 30) #绘制规则图的图形,with_labels决定节点是非带标签(编号),node_size是节点的直径
plt.show() #显示图形

 社会网络_networkX学习(二)

# 二、ER随机图

# ER随机图是早期研究得比较多的一类“复杂”网络,这个模型的基本思想是以概率p连接N个节点中的每一对节点。在NetworkX中,可以用random_graphs.erdos_renyi_graph(n,p)方法生成一个含有n个节点、以概率p连接的ER随机图:

import networkx as nx
import matplotlib.pyplot as plt
ER = nx.random_graphs.erdos_renyi_graph(20,0.2) #生成包含20个节点、以概率0.2连接的随机图
pos = nx.shell_layout(ER)          #定义一个布局,此处采用了shell布局方式
nx.draw(ER,pos,with_labels=False,node_size = 30)
plt.show()

 社会网络_networkX学习(二)

# 三、WS小世界网络

# 在NetworkX中,可以用random_graphs.watts_strogatz_graph(n, k, p)方法生成一个含有n个节点、每个节点有k个邻居、以概率p随机化重连边的WS小世界网络,下面是一个例子:

import networkx as nx
import matplotlib.pyplot as plt
WS = nx.random_graphs.watts_strogatz_graph(20,4,0.3) #生成包含20个节点、每个节点4个近邻、随机化重连概率为0.3的小世界网络
pos = nx.circular_layout(WS)          #定义一个布局,此处采用了circular布局方式
nx.draw(WS,pos,with_labels=False,node_size = 30) #绘制图形
plt.show()

社会网络_networkX学习(二) 

# 四、BA无标度网络

# 在NetworkX中,可以用random_graphs.barabasi_albert_graph(n, m)方法生成一个含有n个节点、每次加入m条边的BA无标度网络,下面是一个例子:

import networkx as nx
import matplotlib.pyplot as plt
BA= nx.random_graphs.barabasi_albert_graph(20,1) #生成n=20、m=1的BA无标度网络
pos = nx.spring_layout(BA)          #定义一个布局,此处采用了spring布局方式
nx.draw(BA,pos,with_labels=False,node_size = 30) #绘制图形
plt.show()

社会网络_networkX学习(二) 

# 五、对BA模型实现代码的分析

# 前面我们介绍了NetworkX提供的4种网络演化模型的应用方法,但仅停留在使用已有的模型是不够的,实际工作中我们可能会自己开发一些网络演化模型。利用NetworkX提供的数据结构,我们可以比较方便的完成这一工作。下面以NetworkX中BA模型的实现代码为例,分析用NetworkX开发网络演化模型的一般思路。NetworkX中关于网络建模的代码在random_graphs.py这个文件中,可以用记事本打开它。为了叙述简便起见,我删掉了原始代码中的一些错误处理与初始条件定义的语句,红色部分是翻译后的注释。
#定义一个方法,它有两个参数:n - 网络节点数量;m - 每步演化加入的边数量
def barabasi_albert_graph(n, m):
    # 生成一个包含m个节点的空图 (即BA模型中t=0时的m0个节点)
    G=empty_graph(m)
    # 定义新加入边要连接的m个目标节点
    targets=range(m)
    # 将现有节点按正比于其度的次数加入到一个数组中,初始化时的m个节点度均为0,所以数组为空
    repeated_nodes=[]    
   # 添加其余的 n-m 个节点,第一个节点编号为m(Python的数组编号从0开始)
    source=m
    # 循环添加节点
    while source<n:
        # 从源节点连接m条边到选定的m个节点targets上(注意targets是上一步生成的)
        G.add_edges_from(zip([source]*m,targets))
        # 对于每个被选择的节点,将它们加入到repeated_nodes数组中(它们的度增加了1)
        repeated_nodes.extend(targets)
        # 将源点m次加入到repeated_nodes数组中(它的度增加了m)
        repeated_nodes.extend([source]*m)
        # 从现有节点中选取m个节点 ,按正比于度的概率(即度优先连接)
        targets=set()
        while len(targets)<m:
            #按正比于度的概率随机选择一个节点,见注释1
            x=random.choice(repeated_nodes)
            #将其添加到目标节点数组targets中
            targets.add(x)       
        #挑选下一个源点,转到循环开始,直到达到给定的节点数n
        source += 1
    #返回所得的图G
    return G

 

 

# 二分图又称二部图,是图论中的一种特殊模型,它的顶点可分割为两个互不相交的子集,并且图中的每条边所关联的两个顶点分别属于这两个不同的顶点集。二分图在复杂网络分析中有很多应用,例如科学家合作网络(作者和论文)、商品网络(商品和购买者)、城市公交网络(线路和站点)等都可以用二分图来进行描述。NetworkX提供了一些基本的二分图建模与分析功能,下面对这些功能作一个简单的介绍。

# 一、建立二分图

# 建立二分图与建立普通的图方法比较类似,需要注意的是,边只能在不同类节点之间添加,同类节点之间不要添加边就可以。下面是一个简单的例子(本例中用1开头的编号表示项目节点,用2开头的编号表示参与者节点):
import networkx as nx
B = nx.Graph()
#添加一个项目101,它有3个参与者:201,202,203
B.add_edge(101,201)
B.add_edge(101,202)
B.add_edge(101,203)
#添加一个项目102,它有2个参与者:203,202,2034
B.add_edge(102,203)
B.add_edge(102,204)
nx.draw(B)

 社会网络_networkX学习(二)

# 此外,
# NetworkX还提供了多种二分图演化模型的建立方法,在这里把它们列出来供大家参考:
# -- networkx.generators.classic.complete_bipartite_graph(n1, n2, create_using=None)--networkx.generators.bipartite.bipartite_configuration_model (aseq, bseq, create_using=None, seed=None)

# 根据两个度序列建立一个二分图
# -- networkx.generators.bipartite.bipartite_random_regular_graph(d, n, create_using=None, seed=None)
# 建立一个随机的规则二分图
# -- networkx.generators.bipartite.bipartite_preferential_attachment_graph(aseq, p, create_using=None, seed=None)
# 建立一个优先连接的二分图
# -- networkx.generators.bipartite.bipartite_havel_hakimi_graph(aseq, bseq, create_using=None)
# 根据两个度序列建立一个Havel-Hakimi模式的二分图(下面两个模型类似,我没有接触过这个模型,不太理解具体含义)
# -- networkx.generators.bipartite.bipartite_reverse_havel_hakimi_graph(aseq, bseq, create_using=None)
# -- networkx.generators.bipartite.bipartite_alternating_havel_hakimi_graph(aseq, bseq, create_using=None)
#http://blog.sciencenet.cn/home.php?mod=space&uid=404069&do=blog&id=335920
#根据值的大小随机选择函数,seq是一个数组,值为正实数。返回数组元素索引
def RanChoice(seq):
    ran = random.random()*sum(seq)
    sumtmp = 0
    N = seq.__len__()
    for i in xrange(N):
        sumtmp += seq[i]
        if sumtmp > ran:
            a = i
            return a
    return -1
test = [ 6.1  ,  2.2  ,  1.7 ]
RanChoice(test)