首发于 交通科研
复杂网络与NetworkX

复杂网络与NetworkX

一、networkx介绍

networkx在2002年5月产生,是一个用Python语言开发的图论与复杂网络建模工具,内置了常用的图与复杂网络分析算法,可以方便的进行复杂网络数据分析、仿真建模等工作。networkx支持创建简单无向图、有向图和多重图;内置许多标准的图论算法,节点可为任意数据;支持任意的边值维度,功能丰富,简单易用。利用networkx可以以标准化和非标准化的数据格式存储网络、生成多种随机网络和经典网络、分析网络结构、建立网络模型、设计新的网络算法、进行网络绘制等。


二、复杂网络介绍

复杂网络(Complex Network),是指具有自组织、自相似、吸引子、小世界、无标度中部分或全部性质的网络。 钱学森 给出了复杂网络的一个较严格的定义:具有 自组织 自相似 吸引子 、小世界、无标度中部分或全部性质的网络称为复杂网络。



三、图的介绍

  • Graph的定义

图是复杂网络研究中的一个重要概念。Graph是用 线 来刻画离散事物集合中的每对事物间以某种方式相联系的数学模型。网络作为图的一个重要领域,包含的概念与定义更多,如有向图网络(Directed Graphs and Networks)、无向图网络(Undirected)等概念。

Graph在现实世界中随处可见,如交通运输图、旅游图、流程图等。利用图可以描述现实生活中的许多事物,如用点可以表示交叉口,点之间的连线表示路径,这样就可以轻而易举的描绘出一个交通运输网络。

  • Graph的结构

根据Graph的定义,一个Graph包含一个节点集合和一个边集。将图表示为可以在计算机中处理的形式常见表示方式:①邻接矩阵②邻接表③三元组

  • Graph分类

Graph:指无向图(undirected Graph),即忽略了两节点间边的方向。

DiGraph:指有向图(directed Graph),即考虑了边的有向性。

MultiGraph:指多重无向图,即两个结点之间的边数多于一条,又允许顶点通过同一条边和自己关联。

MultiDiGraph:多重图的有向版本。

G = nx.Graph() # 创建无向图

G = nx.DiGraph() # 创建有向图

G = nx.MultiGraph() # 创建多重无向图

G = nx.MultiDigraph() # 创建多重有向图

G.clear() #清空图

四、网络的统计指标

度: 节点度是指和该节点相关联的边的条数,又称关联度。特别地,对于有向图,节点的入度 是指进入该节点的边的条数;节点的出度是指从该节点出发的边的条数。

平均路径长度: 平均路径长度是 拓扑网络 中的一个概念,定义为所有可能的网络 节点 对的最短路径上的平均步数。它是网络上信息或大众运输效率的一种度量。

集聚系数: 图论 中,聚类系数是图中节点聚类的程度的度量。有证据表明,在大多数真实世界的网络中,特别是在 社交网络 中,节点往往以相对高密度的联系为特征,形成紧密的群体;这种可能性往往大于两个节点之间随机建立平局的平均概率

节点中心性: 图论 网络分析 中,中心性指标确定图中最重要的 顶点 。应用程序包括识别 社交网络 中最有影响力的人、 互联网 城市网络 中的关键基础设施节点和疾病的 超级传播者 。中心性概念最早出现在 社会网络分析 中,许多衡量中心性的术语反映了它们的 社会学 渊源。它们不应该与 节点影响度量 相混淆,节点影响度量试图量化网络中每个节点的影响。

五、基础教程

#添加节点
import networkx as nx
import matplotlib.pyplot as plt
G = nx.Graph()                 #建立一个空的无向图G
G.add_node('1')                  #添加一个节点1
nx.draw(G, with_labels=True)
plt.show()



G.add_nodes_from(['2','3','4','5'])    #加点集合
nx.draw(G, with_labels=True)
plt.show()



G.add_cycle(['6','7','8','9']) #加环
nx.draw(G, with_labels=True)
plt.show()



H = nx.path_graph(10)          #返回由10个节点挨个连接的无向图,所以有9条边
G.add_nodes_from(H)            #创建一个子图H加入G
G.add_node(H)                  #直接将图作为节点
nx.draw(G, with_labels=True)
plt.show()




#访问节点
print('图中所有的节点', G.nodes())
print('图中节点的个数', G.number_of_nodes())


图中所有的节点 ['1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, <networkx.classes.graph.Graph object at 0x00000240082AE390>] 图中节点的个数 20

G.remove_node(1)    #删除指定节点
G.remove_nodes_from(['2','3','4','5'])    #删除集合中的节点
nx.draw(G, with_labels=True)
plt.show()



#添加边
F = nx.Graph() # 创建无向图
F.add_edge(11,12)   #一次添加一条边
nx.draw(F, with_labels=True)
plt.show()




e=(13,14)        #e是一个元组
F.add_edge(*e) #这是python中解包裹的过程
nx.draw(F, with_labels=True)
plt.show()



F.add_edges_from([(1,2),(1,3)])#通过添加list来添加多条边
nx.draw(F, with_labels=True)
plt.show()



#通过添加任何ebunch来添加边
F.add_edges_from(H.edges()) #不能写作F.add_edges_from(H)
nx.draw(F, with_labels=True)
plt.show()



#访问边
print('图中所有的边', F.edges())
print('图中边的个数', F.number_of_edges()) 



#删除边
F.remove_edge(1,2)
F.remove_edges_from([(11,12), (13,14)])
nx.draw(F, with_labels=True)
plt.show()



#实例:在networkx中列出节点和边
import networkx as nx
import matplotlib.pyplot as plt
G = nx.DiGraph()
G.add_edges_from([('0', '1'), ('0', '2'), ('0', '3')])
G.add_edges_from([('4', '41'), ('1', '11'), ('1', '12'), ('1', '13')])
G.add_edges_from([('2', '21'), ('2', '22')])
G.add_edges_from([('13', '131'), ('22', '221')])
G.add_edges_from([('131', '221'), ('221', '131')])
G.add_nodes_from(['5','6','7','8'])
nx.draw(G, with_labels=True)
plt.show()



六、北京地铁线路实例

北京市地铁线路数据如下所示

data = pd.read_csv("D:\\Metro_Beijing.csv")



LINE代表线路,STATION代表该站点在这条线路的顺序,STATION-NAME是站点名称。为了画出地铁线路网络图,需要对数据进一步处理,可以把它处理成 (边起点,边终点,边的权重) 的形式,边的起点和终点就是地铁站点,边的权重可以根据站点间的实际行程时间和距离来确定,本文为了简便,把边的权重定为1。且为了表达简便。每个站点的NAME用数字代替,数据中共有376个地铁站,所以站点的编号是从1-376。

经过处理后,得到一个三列的数据,NO是边的起点,NO2是边的终点,count是权重,因为地铁线路大部分是双向的,所以这是一个没有方向的无向图。该文件为“SD”


#有向图
G = nx.from_pandas_edgelist(SD, 'NO', 'NO2', 'count', create_using=nx.DiGraph())
pos = nx.spring_layout(G)#### pos是不是可以设置格式
pylab.figure(1)
nx.draw(G, pos, with_labels=False, node_size=100, node_color="skyblue", node_shape="o", alpha=0.5,width=0.5)



#无向图
G = nx.from_pandas_edgelist(SD, 'NO', 'NO2', 'count', create_using=nx.Graph())
pos = nx.spring_layout(G)
pylab.figure(figsize=(12, 8))
nx.draw(G, pos, with_labels=True, node_size=300, node_color="skyblue", node_shape="o",alpha=0.8,width=2)


因为没有加入站点的位置信息,所以绘制的Graph的站点只表示连通关系,不表示真实的位置关系。

绘制好图后,可以对图进行指标的计算:

print(nx.number_of_nodes(G)) #输出图的顶点数
print(nx.number_of_edges(G)) #输出图的边数
print(nx.number_connected_components(G)) #输出图的连通子图数量
lst = list(G.subgraph(c) for c in nx.connected_components(G)) #提取图中所有连通子图,返回一个列表,默认按照结点数量由大到小排序
H = lst[0] #取顶点数最多连通子图来分析