networkx完全指南

  • 2020 年 4 月 29 日
  • AI

虽然很慢,但是作为图算法领域的菜鸟来说,networkx可以帮助快速建立起对图数据的感知,并且其实对于中小型数据集,network是非常好上手的。当然工业级的还得用neo4j搭配graphx,毕竟动辄就是上亿个节点几十亿条边的巨量数据。

networkx主要包含了五个模块:

1、图对象的类;

2、创建标准图的生成器;

3、 在现有数据集中读取的IO接口(比如从csv中读取边和节点的数据);

4、经典的传统图算法(不包含图神经网络系列算法);

5、一些方便的画图函数

networkx支持创建四种图类型:

1、Graph 无向图,允许节点与自身形成闭环;

2、DiGraph 有向图;

3、MultiGraph 多重无向图, 一种灵活的图类,允许节点对之间有多个无向边。 额外的灵活性导致性能的一些下降,不过通常不显著;

4、MultiDiGraph 多重有向图

不同类型的图的定义如下:

 import networkx as nx
>>> G = nx.Graph()
>>> G = nx.DiGraph()
>>> G = nx.MultiGraph()
>>> G = nx.MultiDiGraph()

所有图类都允许任何哈希对象作为节点。 哈希对象包括字符串、元组、整数或是另一个图结构等等。

图内部数据结构基于邻接列表表示,并使用Python字典数据结构实现。

图邻接结构使用 Python的dict来实现;外部字典由节点键控到本身是字典的值,由相邻节点键控到 与该边缘相关联的边缘属性。 这种“dict-of-dict”结构允许快速添加、删除和查找大图中的节点和邻居。 底层数据结构通过类定义中的方法(编程接口“API”)直接访问。


下面介绍使用networkx构建图的流程,首先:

1.2 Graphs

使用Network X时要做的第一选择是使用什么类型的图形对象。 图(网络)是节点的集合,以及作为节点对的边的集合。 属性 通常与节点和/或相关联。networkx支持四种类型的图的构建上面提到过了:

其次:

1.2.1 Nodes and Edges

指定完图类型之后,下一步是指定节点和边的类型, 如果用户关心的是网络的拓扑结构,那么使用整数或字符串作为节点是有意义的,不需要考虑边数据。 如果已经有了描述节点的数据结构,可以简单地使用该结构作为节点,只要它是hashable的。 如果不可散列,则可以使用唯一标识符来表示节点,并将数据分配为节点属性。

边通常有与它们相关的数据。 任意数据可以作为边属性与边相关联。 如果数据是数字的,其意图是表示加权图,则使用“weight” 作为其属性的关键字。 一些图形算法,如Dijkstra的最短路径算法,默认情况下使用这个属性名(“weight”)来获得每个边缘的权重。

属性可以通过在添加边时使用key/value 对来分配给边。 可以使用任何关键字来命名属性,然后可以使用该属性关键字查询边数据。

通过上述的两个流程,我们就定义完毕一张完整的图了。下面介绍实际的代码实现。

1.3 Graph Creation

networkX图对象可以以下三种方式之一创建:

1、 图形生成器 Graph generators -创建网络拓扑的标准方法;

2、 从预先存在的(通常是文件)来源导入数据;

3、 显式添加边缘和节点;

显式添加和删除节点/边缘是最容易描述的。 每个图形对象提供操作图形的方法。 例如:

>>> import networkx as nx
>>> G = nx.Graph()
>>> G.add_edge(1, 2) # default edge data=1
>>> G.add_edge(2, 3, weight=0.9) # specify edge data

add_edge的过程中,默认自动生成对应的节点,例如G.add_edge(1, 2)自动生成型的节点1和2,而G.add_edge(2, 3, weight=0.9)则自动生成节点3,因为节点2上一步已经生成过程,并且这里是增加了带权的边,权重为0.9

边属性可以是任何hashable的对象:

>>> import math
>>> G.add_edge('y', 'x', function=math.cos)
>>> G.add_node(math.cos) # any hashable can be a node

你可以同时添加很多边:

>>> elist = [(1, 2), (2, 3), (1, 4), (4, 2)]
>>> G.add_edges_from(elist)
>>> elist = [('a', 'b', 5.0), ('b', 'c', 3.0), ('a', 'c', 1.0), ('c', 'd', 7.3)]
>>> G.add_weighted_edges_from(elist)

上述是添加无权边和带权边的两种方式,无权边的默认权重是1.0;

1.4 Graph Reporting

类视图提供节点,邻居,边和度的基本报告. 这些视图提供了属性的迭代以及成员查询和数据属性查找的方法。 视图是指图形数据结构,因此对图形的更改反映在视图中。这类似于Python3中的字典视图。 如果您想在迭代时更改图形,则需要使用例如。 (for e in list(G.edges):)的方法来处理, 视图提供类似集合的操作,例如。 联合与交叉,以及类似dict的数据属性的查找和迭代,G.edges[u, v][‘color’] and for e, datadict in G.edges.items(),方法G.edges.items()和G.edges.values()是熟悉的pythonDicts api的形式。

边的基本图形关系可以通过两种方式得到.:寻找节点的邻居,也可以寻找边, 我们开玩笑地定义:关注节点/邻居的人是以节点为中心的,关注边缘的人是以边缘为中心的, networkX的设计者倾向于以节点为中心,并将边视为节点之间的关系。 可以通过选择查找符号来看到这一点,例如G[u]提供邻居(邻接),而边查找是G.edges[u,v]。稀疏图的大多数数据结构本质上是邻接列表(adjacency lists),因此符合这一观点。 最后,当然,用哪种方式检查图表并不重要。 G.edges 重复表示无向边(无向边等价于双向边,通过这种方式来统一两种便类型),而neighbor reporting 显示节点的两个方向的所有领节点。

任何比边、邻居和度更复杂的属性都是由函数提供的,例如 nx.triangles(G, n),返回在图G上,n节点所在的三角关系的数量。这些函数都统一在networkx的algorithms模块。

1.5 Algorithms

一些图算法提供了网络X。 其中包括最短路径、广度优先搜索(参见遍历)、聚类和同构算法等。 例如,使用Dijkstra算法找到最短加权路径的代码:

>>> G = nx.Graph()
>>> e = [('a', 'b', 0.3), ('b', 'c', 0.9), ('a', 'c', 0.5), ('c', 'd', 1.2)]
>>> G.add_weighted_edges_from(e)
>>> print(nx.dijkstra_path(G, 'a', 'd'))
['a', 'c', 'd']

1.6 Drawing

基本绘图函数基本上使用通过字典提供的位置将节点放置在散点图上,或者使用布局函数计算位置。使用的是graphiz和pydot来进行建议画图,至于画图的拓展,可以借助外部软件。

>>> import matplotlib.pyplot as plt
>>> G = nx.cubical_graph()
>>> plt.subplot(121)
<matplotlib.axes._subplots.AxesSubplot object at ...>
>>> nx.draw(G) # default spring_layout
>>> plt.subplot(122)
<matplotlib.axes._subplots.AxesSubplot object at ...>
>>> nx.draw(G, pos=nx.circular_layout(G), node_color='r', edge_color='b')

1.7 Data Structure

networkx使用 字典-字典-字典。。。这样的符合结构来作为构建图的基础数据结构, 这允许快速查找,并对大型稀疏网络进行合理的存储。 键是节点,因此G[u]返回一个邻接字典,该邻接字典由边缘属性字典的邻居键。

键是节点,因此G[u]返回u的邻节点,以领接字典的形式展现,通过list( G.adj.items())可以很直观的看到整个图的领接情况。

表达式G[u][v]返回边属性字典本身。优势:

下面是一个例子:

>>> G = nx.Graph()
>>> G.add_edge('A', 'B')
>>> G.add_edge('B', 'C')
>>> print(G.adj)
{'A': {'B': {}}, 'B': {'A': {}, 'C': {}}, 'C': {'B': {}}}

这里介绍了另外两种图类型的实现机制。

图提供了边数据属性的两个接口:adjacency and edges。 因此,G[u][v][‘wid h’]与G.edges[u,v][‘width’]作用是相同的。

>>> G = nx.Graph()
>>> G.add_edge(1, 2, color='red', weight=0.84, size=300)
>>> print(G[1][2]['size'])
300
>>> print(G.edges[1, 2]['color'])
red

NetworkX提供了用于存储图形的数据结构和方法。

所有NetworkX图形类都允许(可哈希)Python对象作为节点,并且任何Python对象都可以设定为边属性。图类的选择取决于您要表示的图的结构。

见名知意。

2.2 Basic graph types

2.2.1 Graph—Undirected graphs with self loops

class Graph(incoming_graph_data=None, **attr) 源码文档

Base class for undirected graphs.

A Graph stores nodes and edges with optional data, or attributes.

Graphs hold undirected edges. Self loops are allowed but multiple (parallel) edges are not.

Nodes can be arbitrary (hashable) Python objects with optional key/value attributes. By convention None is not used as a node.

Edges are represented as links between nodes with optional key/value attributes.

Parameters

incoming_graph_data (input graph (optional, default: None)) – Data to initialize graph. If None (default) an empty graph is created. The data can be any format that is supported by the to_networkx_graph() function, currently including edge list, dict of dicts, dict of lists,

NetworkX graph, NumPy matrix or 2d ndarray, SciPy sparse matrix, or PyGraphviz graph.

attr (keyword arguments, optional (default= no attributes)) – Attributes to add to graph as key=value pairs.

See also:

DiGraph, MultiGraph, MultiDiGraph, OrderedGraph

下面是一些简单的示例:

属性图:

每个图,节点和边都可以在关联的属性字典中保存键/值属性对(键必须是可哈希的)。 默认情况下,这些为空,但可以使用add_edge,add_node或直接操作分别名为graph,node和edge的属性字典进行添加或更改。

networkx和neo4j一样使用的是属性图。基本的nodes和edges构成graph,并且nodes,edges,graph都以字典的形式存储其属性。

下面是一些示例:

Shortcuts:

Many common graph features allow python syntax to speed reporting.

通常,遍历图形所有边的最佳方法是通过邻居。 The neighbors are reported as an adjacency-dict G.adj or G.adjacency() ,也就是通过Graph的领结矩阵的方式便利最快捷方便:

>>> for n, nbrsdict in G.adjacency():
... for nbr, eattr in nbrsdict.items():
... if 'weight' in eattr:
... # Do something useful with the edges
... pass

But the edges() method is often more convenient:

>>> for u, v, weight in G.edges.data('weight'):
... if weight is not None:
... # Do something useful with the edges
... pass

算了,随缘翻译吧