network是一个用Python语言开发的图论与复杂网络建模工具,内置了常用的图与复杂网络分析算法,可以方便的进行复杂网络数据分析、仿真建模等工作。

networkx支持创建简单无向图、有向图和多重图;内置许多标准的图论算法,节点可为任意数据;支持任意的边值维度,功能丰富,简单易用。

1、Graph

在NetworkX中,一个节点可以是任意hash对象(除了None对象),一条边也可以关联任意的对象,像一个文本字符串,一幅图像,一个XML对象,甚至是另一个图或任意定制的节点对象。

1.1 Graph分类

Graph:指无向图(undirected Graph),即忽略了两节点间边的方向。
DiGraph:指有向图(directed Graph),即考虑了边的有向性。
MultiGraph:指多重无向图,即两个结点之间的边数多于一条,又允许顶点通过同一条边和自己关联。
MultiDiGraph:多重图的有向版本

import networkx as nx

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

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

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

G4 = nx.MultiDiGraph();#创建多重有向图

G1.clear();#清空图

基本操作:

1.无向图

1.1 节点添加与删除

G = nx.Graph() #创建无向图
G.add_node('a')#添加单个节点
G.add_nodes_from(['b','c','d','e']) #添加多个节点,以集合的方式添加
H = nx.path_graph(10) #返回由10个节点挨个连接的无向图,所以有9条边

如下所示:

python network 方法 network库python_Graph

G.add_nodes_from(H) #创建一个子图H加入G
G.add_node(H) #直接将图作为节点
nx.draw(H, with_labels=True)
plt.show() #显示图

遍历节点和输出图中节点的个数

print('图中所有的节点', G.nodes())

print('图中节点的个数', G.number_of_nodes())

删除节点:

G.remove_node(1)    #删除指定节点
G.remove_nodes_from(['b','c','d','e'])    #删除集合中的节点

nx.draw(G, with_labels=True)

plt.show()

2.边

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

#等价于
e=(13,14)
F.add_edge(*e) #python解包裹的过程

在传递tuple时,让tuple的每一个元素对应一个位置参数。在调用func时使用*,把args拆成分散的三个元素,分别传递给a,b,c。

F.add_edges_from([(1,2),(1,3)]) #通过添加list来添加多条边
H = nx.path_graph(10)

#通过添加任何ebunch来添加边
F.add_edges_from(H.edges()![在这里插入图片描述](https://img-blog.csdnimg.cn/20210117202830651.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTcyMDc1MQ==,size_16,color_FFFFFF,t_70)


nx.draw(F,with_labels=True)
plt.show()

遍历输出所有的边和边数

print('图中所有的边', F.edges())

print('图中边的个数', F.number_of_edges())

遍历输出每条边及其权重,可用邻接迭代器实现
对于无向图,每一条边相当于两条有向边

FG = nx.Graph() #创建无向图
FG.add_weighted_edges_from([(1,2,0.125),(1,3,0.75),(2,4,1.2),(3,4,0.275)])

#n为节点名称 nbrs为邻接矩阵的边和权重
for n,nbrs in FG.adjacency():
	#nbr为与n相连的另一个点 eattr为权重
    for nbr,eattr in nbrs.items():
        data = eattr['weight']
        print('(%d, %d, %0.3f)' % (n,nbr,data))

print("********")

n为节点名称 nbrs为邻接矩阵的边和权重

python network 方法 network库python_Graph_02

#筛选weight小于0.5的边:
FG = nx.Graph()
FG.add_weighted_edges_from([(1,2,0.125), (1,3,0.75), (2,4,1.2), (3,4,0.275)])
for n, nbrs in FG.adjacency():
    for nbr, eattr in nbrs.items():
        data = eattr['weight']
        if data < 0.5:
            print('(%d, %d, %0.3f)' % (n,nbr,data))

不重复的访问所有边:

for u,v,d in FG.edges(data = 'weight'):
    print((u,v,d))

3.属性

属性诸如weight,labels,colors,或者任何对象,你都可以附加到图、节点或边上。

对于每一个图、节点和边都可以在关联的属性字典中保存一个(多个)键-值对。

默认情况下这些是一个空的字典,但是我们可以增加或者是改变这些属性。

G = nx.Graph(day='Monday')    #可以在创建图时分配图的属性
print(G.graph)

G.graph['day'] = 'Friday'     #也可以修改已有的属性
print(G.graph)

G.graph['name'] = 'time'      #可以随时添加新的属性到图中
print(G.graph)

为节点添加属性:

G = nx.Graph(day='Monday')
G.add_node(1, index='1th')             #在添加节点时分配节点属性
print(G.nodes(data=True))

为节点修改属性:

G.nodes[1]['index'] = '0th'             #通过G.node[][]来添加或修改属性
print(G.nodes(data=True))

为集合中的节点添加属性

G.add_nodes_from([2,3], index='2/3th') #从集合中添加节点时分配属性
print(G.nodes(data=True))

为边添加属性:

G = nx.Graph(day='manday')
G.add_edge(1,2,weight=10)                    #在添加边时分配属性
print(G.edges(data=True))

对集合中的边添加属性:

添加相同属性:

G.add_edges_from([(1,3), (4,5)], len=22)     #从集合中添加边时分配属性
print(G.edges(data='len'))

添加不同的属性:

G.add_edges_from([(3,4,{'hight':10}),(1,4,{'high':'unknow'})])
print(G.edges(data=True))

修改属性:

G[1][2]['weight'] = 100000                   #通过G[][][]来添加或修改属性
print(G.edges(data=True))

其他图:

有向图和多重图的操作与无向图一致:

#有向图转化成无向图

H=DG.to_undirected()
#或者
H=nx.Graph(DG)

#无向图转化成有向图

F = H.to_directed()
#或者
F = nx.DiGraph(H)

关于图的函数:

degree(G[, nbunch, weight]):返回单个节点或nbunch节点的度数视图。

degree_histogram(G):返回每个度值的频率列表。

density(G):返回图的密度。

info(G[, n]):打印图G或节点n的简短信息摘要。

create_empty_copy(G[, with_data]):返回图G删除所有的边的拷贝。

is_directed(G):如果图是有向的,返回true。

add_star(G_to_add_to, nodes_for_star, **attr):在图形G_to_add_to上添加一个星形。

add_path(G_to_add_to, nodes_for_path, **attr):在图G_to_add_to中添加一条路径。

add_cycle(G_to_add_to, nodes_for_cycle, **attr):向图形G_to_add_to添加一个循环。

关于节点的函数:

nodes(G):在图节点上返回一个迭代器。

number_of_nodes(G):返回图中节点的数量。

all_neighbors(graph, node):返回图中节点的所有邻居。

non_neighbors(graph, node):返回图中没有邻居的节点。

common_neighbors(G, u, v):返回图中两个节点的公共邻居。

关于边的函数:

edges(G[, nbunch]):返回与nbunch中的节点相关的边的视图。

number_of_edges(G):返回图中边的数目。

non_edges(graph):返回图中不存在的边。

关于函数使用的实例:

初始化一个有向图:

G = nx.DiGraph()
G.add_edges_from([('n', 'n1'), ('n', 'n2'), ('n', 'n3')])
G.add_edges_from([('n4', 'n41'), ('n1', 'n11'), ('n1', 'n12'), ('n1', 'n13')])
G.add_edges_from([('n2', 'n21'), ('n2', 'n22')])
G.add_edges_from([('n13', 'n131'), ('n22', 'n221')])
G.add_edges_from([('n131', 'n221'), ('n221', 'n131')])
G.add_node('n5')
nx.draw(G, with_labels=True)
plt.show()

图像如下:

python network 方法 network库python_python network 方法_03

1.输出所有有子项的节点

#输出k为节点,v为该节点的度数
for k,v in G.out_degree():
    if v > 0:
        print(k)

2.输出所有没有孩子的节点

for k,v in G.out_degree():
    if v == 0:
        print(k)

经典图论算法:
寻找最小路径:

#自定义网络
row=np.array([0,0,0,1,2,3,6])
col=np.array([1,2,3,4,5,6,7])
value=np.array([1,2,1,8,1,3,5])

print('生成一个空的有向图')
G=nx.DiGraph()

print('为这个网络添加节点...')
#边值为7个 节点则比边多一个
for i in range(0,np.size(col)+1):
    G.add_node(i)
print('在网络中添加带权中的边...')
#row[i]是出发点 col[i]是到达点
for i in range(np.size(row)):
 G.add_weighted_edges_from([(row[i],col[i],value[i])])

print('给网路设置布局...')
pos=nx.shell_layout(G)
print('画出网络图像:')
nx.draw(G,pos,with_labels=True, node_color='white', edge_color='red', node_size=400, alpha=0.5 )
pylab.title('Self_Define Net',fontsize=15)
pylab.show()


'''
Shortest Path with dijkstra_path
'''
print('dijkstra方法寻找最短路径:')
path=nx.dijkstra_path(G, source=0, target=7)
print('节点0到7的路径:', path)
print('dijkstra方法寻找最短距离:')
distance=nx.dijkstra_path_length(G, source=0, target=7)
print('节点0到7的距离为:', distance)

python network 方法 network库python_无向图_04

运用布局:
circular_layout:节点在一个圆环上均匀分布
random_layout:节点随机分布
shell_layout:节点在同心圆上分布
spring_layout: 用Fruchterman-Reingold算法排列节点(样子类似多中心放射状)
spectral_layout:根据图的拉普拉斯特征向量排列节点

最小生成树算法:
最小生成树:一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。

#G为图 s为开始节点
def prim(G, s):
    dist = {}   # dist记录到节点的最小距离
    parent = {} # parent记录最小生成树的双亲表
    Q = list(G.nodes()) # Q包含所有未被生成树覆盖的节点
    MAXDIST = 9999.99    # MAXDIST表示正无穷,即两节点不邻接

    # 初始化数据
    # 所有节点的最小距离设为MAXDIST,父节点设为None
    for v in G.nodes():
        dist[v] = MAXDIST
        parent[v] = None
    # 到开始节点s的距离设为0
    dist[s] = 0

    # 不断从Q中取出“最近”的节点加入最小生成树
    # 当Q为空时停止循环,算法结束
    while Q:
        # 取出“最近”的节点u,把u加入最小生成树
        u = Q[0]
        for v in Q:
            if (dist[v] < dist[u]):
                u = v
        Q.remove(u)

        # 更新u的邻接节点的最小距离
        for v in G.adj[u]:
            if (v in Q) and (G[u][v]['weight'] < dist[v]):
                parent[v] = u
                dist[v] = G[u][v]['weight']
    # 算法结束,以双亲表的形式返回最小生成树
    return parent

运行以下代码:

tree = prim(G, 0) #从0点开始生成最小生成树
#tree 的输出为{0: None, 1: 0, 2: 0, 3: 0, 4: 1, 5: 2, 6: 3, 7: 6}
mtg = nx.Graph()
mtg.add_edges_from(tree.items())
mtg.remove_node(None) #去掉值为none的点

nx.draw(mtg,with_labels=True)
plt.show()

python network 方法 network库python_Graph_05

最大联通子图及联通子图规模排序:

G = nx.path_graph(4);
G.add_edges_from([(10,11),(11,12)])
nx.draw(G, with_labels=True, node_size=1000, font_size=20)
plt.show()
# [print(len(c)) for c in sorted(nx.connected_components(G),key=len,reverse=True)]
for c in sorted(nx.connected_components(G), key=len, reverse=True):
    print(c)  # 看看返回来的是什么?结果是{0,1,2,3}
    print(type(c))  # 类型是set
    print(len(c))  # 长度分别是4和3(因为reverse=True,降序排列)

largest_components = max(nx.connected_components(G), key=len)  # 高效找出最大的联通成分,其实就是sorted里面的No.1
print(largest_components)  # 找出最大联通成分,返回是一个set{0,1,2,3}
print(len(largest_components))  # 4