networkx学习笔记

networkX

创建一个图

首先创建一个没有节点没有边的空图

1
2
import networkx as nx
G = nx.Graph()

根据图的定义,一个图包含一个节点集合和一个边集合。在NetworkX中,节点可以是任何哈希对象,比如一个字符串,一幅图像,一个XML对象,甚至是另一个图或者任意定制的节点对象。

注:Python中的None对象不能作为节点的类型。

节点

图可以以多种形式扩张。NetworkX包括许多图生成函数工具,用于读取和写入多种格式的图。

作为简单开始,可以每次添加一个节点:

1
G.add_node(1)

或者从可迭代容器(如列表)中添加多个节点:

1
G.add_node([2,3])

你也可以同时添加包含节点属性的节点:

1
2
3
4
G.add_node([
(4,{"color":"red"}),
(5,{"color":"green"})
])

一个图中的节点可以合并到另一个图中:

1
2
H = nx.path_graph(10)
G.add_nodes_from(H)

现在图G中包含了原来图H中的节点。你也可以将整个图H作为图G中的一个节点

1
G.add_node(H)

现在图G将图H整体作为一个节点。这种灵活性非常强大,因为它允许图形组成图形、文件组成图形、函数组成图形等等。值得考虑的是如何构造应用程序,使节点成为有用的实体。当然,如果您愿意,您总是可以在中使用唯一标识符,并使用单独的字典根据标识符对节点信息进行键控。

图也可以以加边的方式增长:

1
2
3
G.add_edge(1, 2)
e = (2, 3)
G.add_edge(*e) # unpack edge tuple*

通过边的列表增长:

1
G.add_edges_from([(1, 2), (1, 3)])

或者通过添加任何边的ebunch

ebunch是边的元组的任何可迭代容器。边的元组可以是2元组节点,也可以是3元组,在第2个节点后面加上边的属性字典,例如(2,3,{'weight':3.1415})

1
G.add_edges_from(H.edges)

添加现有节点或边时没有任何冲突。例如,删除所有节点和边后,

1
G.clear()

在添加新的节点/边时,NetworkX悄悄地忽略任何已经存在的。

1
2
3
4
5
6
G.add_edges_from([(1, 2), (1, 3)])
G.add_node(1)
G.add_edge(1, 2)
G.add_node("spam") # adds node "spam"
G.add_nodes_from("spam") # adds 4 nodes: 's', 'p', 'a', 'm'
G.add_edge(3, 'm')

此时,图由 8 个节点和 3 条边组成,如下所示

1
2
3
4
>>> G.number_of_nodes()
8
>>> G.number_of_edges()
3

注:邻接报告的顺序(例如,G.adj,G.successorsG.predecessors)是 边缘添加。但是,G.edge 的顺序是邻接的顺序 其中包括节点的顺序和每个节点 节点的邻接关系。请参阅以下示例:

1
2
3
4
5
6
7
DG = nx.DiGraph()
DG.add_edge(2, 1) # adds the nodes in order 2, 1
DG.add_edge(1, 3)
DG.add_edge(2, 4)
DG.add_edge(1, 2)
assert list(DG.successors(2)) == [1, 4]
assert list(DG.edges) == [(2, 1), (2, 4), (1, 3), (1, 2)]

检查图的元素

我们可以检查节点和边。四个基本图属性有助于报告:G.nodesG.edgesG.adjG.degree 。这些图中节点、边、相邻(邻接)和节点的度的集合视图。它们为图形结构提供了一个不断更新的只读视图。它们也是类似于dict,因为您可以查找节点和边数据属性通过使用方法.items().data()迭代数据属性。 如果您需要一个特定的容器类型而不是视图,可以指定一个。 这里我们使用列表,尽管集合、字典、元组和其他容器在其他情况下可能会更好。G.nodes G.edges G.adj G.degree .items() .data()

1
2
3
4
5
6
7
8
>>> list(G.nodes)
[1, 2, 3, 'spam', 's', 'p', 'a', 'm']
>>> list(G.edges)
[(1, 2), (1, 3), (3, 'm')]
>>> list(G.adj[1]) # or list(G.neighbors(1))
[2, 3]
>>> G.degree[1] # the number of edges incident to 1
2

从图形中删除元素

可以采用与添加类似的方式从图形中删除节点和边。 使用方法 Graph.remove_node()Graph.remove_nodes_from()Graph.remove_edge()Graph.remove_edges_from()例如

1
2
3
4
5
>>> G.remove_node(2)
>>> G.remove_nodes_from("spam")
>>> list(G.nodes)
[1, 3, 'spam']
>>> G.remove_edge(1, 3)

使用图形构造函数

图形对象不只是用增量方式构建 - 指定图形结构的数据可以直接传递给各种图形类构造函数。 通过实例化其中一个图创建图结构时,您 可以指定多种格式的数据。

1
2
3
4
5
6
7
8
9
10
11
12
>>> G.add_edge(1, 2)
>>> H = nx.DiGraph(G) # create a DiGraph using the connections from G
>>> list(H.edges())
[(1, 2), (2, 1)]
>>> edgelist = [(0, 1), (1, 2), (2, 3)]
>>> H = nx.Graph(edgelist) # create a graph from an edge list
>>> list(H.edges())
[(0, 1), (1, 2), (2, 3)]
>>> adjacency_dict = {0: (1, 2), 1: (0, 2), 2: (0, 1)}
>>> H = nx.Graph(adjacency_dict) # create a Graph dict mapping nodes to nbrs
>>> list(H.edges())
[(0, 1), (0, 2), (1, 2)]

用作节点和边的内容

您可能会注意到节点和边未指定为 NetworkX 对象。这使您可以自由地使用有意义的项作为节点和边。最常见的选择是数字或字符串,但节点可以是任何可哈希对象(除了None),并且可以使用的G.add_edge(n1, n2, object=x) 将边与任何对象x关联。

例如,可以是来自RCSB蛋白质 数据库的蛋白质对象,而x可以参考详细说明的出版物的XML记录,详细说明了它们相互作用的实验观察结果。

我们发现这种力量非常有用, 除非熟悉 Python,否则被滥用可能会导致令人惊讶的行为。 如有疑问,请考虑使用 convert_node_labels_to_integers() 获取带有整数标签的更传统的图。

访问边和邻接点

除了视图 Graph.edge Graph.adj 之外, 可以使用下标表示法访问边和相邻点。

1
2
3
4
5
6
7
>>> G = nx.Graph([(1, 2, {"color": "yellow"})])
>>> G[1] # same as G.adj[1]
AtlasView({2: {'color': 'yellow'}})
>>> G[1][2]
{'color': 'yellow'}
>>> G.edges[1, 2]
{'color': 'yellow'}

您可以使用下标表示法获取/设置边的属性 如果边缘已存在。

1
2
3
4
5
>>> G.add_edge(1, 3)
>>> G[1][3]['color'] = "blue"
>>> G.edges[1, 2]['color'] = "red"
>>> G.edges[1, 2]
{'color': 'red'}

使用G.adjacency()G.adj.items()实现对所有(节点、邻接)对的快速检查。 请注意,对于无向图,邻接迭代会看到每条边两次。

1
2
3
4
5
6
7
8
9
10
>>> FG = nx.Graph()
>>> FG.add_weighted_edges_from([(1, 2, 0.125), (1, 3, 0.75), (2, 4, 1.2), (3, 4, 0.375)])
>>> for n, nbrs in FG.adj.items():
... for nbr, eattr in nbrs.items():
... wt = eattr['weight']
... if wt < 0.5: print(f"({n}, {nbr}, {wt:.3})")
(1, 2, 0.125)
(2, 1, 0.125)
(3, 4, 0.375)
(4, 3, 0.375)

通过 edge 属性可以方便地访问所有边。

1
2
3
4
5
>>> for (u, v, wt) in FG.edges.data('weight'):
... if wt < 0.5:
... print(f"({u}, {v}, {wt:.3})")
(1, 2, 0.125)
(3, 4, 0.375)

向图形、节点和边添加属性

如权重、标签、颜色或任何你喜欢的 Python 对象, 可以附加到图形、节点或边上。

每个图、节点和边都可以在关联的属性字典中保存键值对(键必须是可哈希的)。默认情况下,这些是空的, 但可以使用add_edgeadd_node或直接添加G.graphG.nodesG.edges的属性字典来添加或更改属性。

图属性

创建新图时分配图属性

1
2
3
>>> G = nx.Graph(day="Friday")
>>> G.graph
{'day': 'Friday'}

或者您可以稍后修改属性

1
2
3
>>> G.graph['day'] = "Monday"
>>> G.graph
{'day': 'Monday'}

节点属性

使用add_node()add_nodes_from()G.nodes添加节点属性

1
2
3
4
5
6
7
>>> G.add_node(1, time='5pm')
>>> G.add_nodes_from([3], time='2pm')
>>> G.nodes[1]
{'time': '5pm'}
>>> G.nodes[1]['room'] = 714
>>> G.nodes.data()
NodeDataView({1: {'time': '5pm', 'room': 714}, 3: {'time': '2pm'}})

请注意,将节点添加到G.nodes不会将其添加到图形中,G.add_node()用于添加新节点。边也是如此。

边属性

使用add_edge()add_edges_from()或下标表示法添加或更改边属性。

1
2
3
4
5
>>> G.add_edge(1, 2, weight=4.7 )
>>> G.add_edges_from([(3, 4), (4, 5)], color='red')
>>> G.add_edges_from([(1, 2, {'color': 'blue'}), (2, 3, {'weight': 8})])
>>> G[1][2]['weight'] = 4.7
>>> G.edges[3, 4]['weight'] = 4.2

特殊属性weight应为数字,因为它被需要加权边的算法使用。

有向图

DiGraph 类提供了特定于有向边的其他方法和属性,例如DiGraph.out_edgesDiGraph.in_degreeDiGraph.predecessorsDiGraph.successors等。为了使算法能够轻松地处理这两个类,有向版本的neighbors等同于successors,而degreein_degreeout_degree,尽管有时可能会感到不一致。

1
2
3
4
5
6
7
8
9
10
>>> DG = nx.DiGraph()
>>> DG.add_weighted_edges_from([(1, 2, 0.5), (3, 1, 0.75)])
>>> DG.out_degree(1, weight='weight')
0.5
>>> DG.degree(1, weight='weight')
1.25
>>> list(DG.successors(1))
[2]
>>> list(DG.neighbors(1))
[2]

有些算法仅适用于有向图,而另一些算法对有向图没有很好的定义 。将有向图和无向图混在一起是危险的。如果你想将有向图作为无向图的某些测量,您可能应该使用Graph.to_undirected()将有向图作为无向图,或者使用

1
H = nx.Graph(G)  # create an undirected graph H from a directed graph G

获得无向图。

多图

NetworkX 提供了允许任意一对节点之间存在多条边的图类。 MultiGraph 和 MultiDiGraph 类允许您添加相同的边两次,可能使用不同的边数据。 这对于某些应用程序来说可能很强大,但许多算法在此类图上没有很好地定义。 在结果定义明确的地方,例如 MultiGraph.degree() 我们提供了函数。 否则,您应该以使测量明确定义的方式转换为标准图表。

1
2
3
4
5
6
7
8
9
10
11
12
>>> MG = nx.MultiGraph()
>>> MG.add_weighted_edges_from([(1, 2, 0.5), (1, 2, 0.75), (2, 3, 0.5)])
>>> dict(MG.degree(weight='weight'))
{1: 1.25, 2: 1.75, 3: 0.5}
>>> GG = nx.Graph()
>>> for n, nbrs in MG.adjacency():
... for nbr, edict in nbrs.items():
... minvalue = min([d['weight'] for d in edict.values()])
... GG.add_edge(n, nbr, weight = minvalue)

>>> nx.shortest_path(GG, 1, 3)
[1, 2, 3]

图生成器和图操作

除了逐节点或逐边构造图之外,它们还可以通过以下方式生成

1. 应用经典的图操作,例如:

方法 介绍
subgraph(G, nbunch) Returns the subgraph induced on nodes in nbunch.
union(G, H[, rename, name]) Return the union of graphs G and H.
disjoint_union(G, H) Return the disjoint union of graphs G and H.
cartesian_product(G, H) Returns the Cartesian product of G and H.
compose(G, H) Returns a new graph of G composed with H.
complement(G) Returns the graph complement of G.
create_empty_copy(G[, with_data]) Returns a copy of the graph G with all of the edges removed.
to_undirected(graph) Returns an undirected view of the graph graph.
to_directed(graph) Returns a directed view of the graph graph.

2. 对经典小图进行调用

方法 介绍
petersen_graph([create_using]) Returns the Petersen graph.
tutte_graph([create_using]) Returns the Tutte graph.
sedgewick_maze_graph([create_using]) Return a small maze with a cycle.
tetrahedral_graph([create_using]) Returns the 3-regular Platonic Tetrahedral graph.

3. 为经典图使用(constructive)生成器

方法 介绍
complete_graph(n[, create_using]) Return the complete graph K_n with n nodes.
complete_bipartite_graph(n1, n2[, create_using]) Returns the complete bipartite graph K_{n_1,n_2}.
barbell_graph(m1, m2[, create_using]) Returns the Barbell Graph: two complete graphs connected by a path.
lollipop_graph(m, n[, create_using]) Returns the Lollipop Graph; K_m connected to P_n.

像这样

1
2
3
4
K_5 = nx.complete_graph(5)
K_3_5 = nx.complete_bipartite_graph(3, 5)
barbell = nx.barbell_graph(10, 10)
lollipop = nx.lollipop_graph(10, 20)

4. 使用随机图生成器,

方法 介绍
erdos_renyi_graph(n, p[, seed, directed]) Returns a Gn,p random graph, also known as an Erdős-Rényi graph or a binomial graph.
watts_strogatz_graph(n, k, p[, seed]) Returns a Watts–Strogatz small-world graph.
barabasi_albert_graph(n, m[, seed, …]) Returns a random graph using Barabási–Albert preferential attachment
random_lobster(n, p1, p2[, seed]) Returns a random lobster graph.

像这样

1
2
3
4
er = nx.erdos_renyi_graph(100, 0.15)
ws = nx.watts_strogatz_graph(30, 3, 0.1)
ba = nx.barabasi_albert_graph(100, 5)
red = nx.random_lobster(100, 0.9, 0.9)

5. 使用常用图形格式读取存储在文件中的图形

NetworkX 支持许多流行的格式,例如边缘列表、邻接列表、GML、GraphML、pickle、LEDA 等。

1
2
nx.write_gml(red, "path.to.file")
mygraph = nx.read_gml("path.to.file")

有关图形格式的详细信息,请参阅读和写图形;有关图形生成器函数,请参阅图形生成器

分析图

可以使用各种图论函数来分析图G 的结构,例如:

1
2
3
4
5
6
7
8
9
>>> G = nx.Graph()
>>> G.add_edges_from([(1, 2), (1, 3)])
>>> G.add_node("spam") # adds node "spam"
>>> list(nx.connected_components(G))
[{1, 2, 3}, {'spam'}]
>>> sorted(d for n, d in G.degree())
[0, 1, 1, 2]
>>> nx.clustering(G)
{1: 0, 2: 0, 3: 0, 'spam': 0}

一些具有大输出的函数迭代 (node, value) 2 元组。 如果您愿意,这些很容易存储在 dict 结构中。

1
2
3
>>> sp = dict(nx.all_pairs_shortest_path(G))
>>> sp[3]
{3: [3], 1: [3, 1], 2: [3, 1, 2]}

有关支持的图形算法的详细信息,请参阅算法

绘制图

NetworkX 主要不是一个图形绘图包,而是包含使用 Matplotlib 的基本绘图以及使用开源 Graphviz 软件包的接口。 这些是 networkx.drawing 模块的一部分,如果可能,将被导入。

首先导入 Matplotlib 的绘图接口(pylab 也可以)

1
import matplotlib.pyplot as plt

要测试 nx_pylab 是否成功导入,请使用以下方法之一绘制图G

1
2
3
4
5
G = nx.petersen_graph()
subax1 = plt.subplot(121)
nx.draw(G, with_labels=True, font_weight='bold')
subax2 = plt.subplot(122)
nx.draw_shell(G, nlist=[range(5, 10), range(5)], with_labels=True, font_weight='bold')

交互式操作时上述图像会自动展示。 请注意如果您没有在交互模式下使用 matplotlib,您可能需要下面命令展示图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
plt.show()  

options = {
'node_color': 'black',
'node_size': 100,
'width': 3,
}
subax1 = plt.subplot(221)
nx.draw_random(G, **options)
subax2 = plt.subplot(222)
nx.draw_circular(G, **options)
subax3 = plt.subplot(223)
nx.draw_spectral(G, **options)
subax4 = plt.subplot(224)
nx.draw_shell(G, nlist=[range(5,10), range(5)], **options)

您可以通过 draw_networkx() 找到其他选项,并通过布局模块找到布局。 您可以通过 draw_shell() 使用多个 shell。

1
2
3
G = nx.dodecahedral_graph()
shells = [[2, 3, 4, 5, 6], [8, 1, 0, 19, 18, 17, 16, 15, 14, 7], [9, 10, 11, 12, 13]]
nx.draw_shell(G, nlist=shells, **options)

要将图形保存到文件中,请使用,例如

1
2
nx.draw(G)
plt.savefig("path.png")

此函数写入本地目录中的文件 path.png。 如果 Graphviz 和 PyGraphviz 或 pydot 在您的系统上可用,您还可以使用 networkx.drawing.nx_agraph.graphviz_layoutnetworkx.drawing.nx_pydot.graphviz_layout 来获取节点位置,或者以点格式编写图形以进行进一步处理。


networkx学习笔记
http://jiqingjiang.github.io/p/a75be723/
作者
Jiqing
发布于
2023年2月27日
许可协议