目录:
- 属性映射 -- 内部属性映射
- 图的I/O
- 构建一个 Price网络(例)
名词解释:
Property maps:属性映射 PropertyMap:一个类 scalar value types:标量值类型 pickle module: scale-free graph:属性映射
属性映射是一种将额外信息与顶点、边或图本身相关联的方式。
因此有这样三种类型的属性映射:顶点、边和图。 它们都是由同一个类来操作:PropertyMap。 每个创建了的属性映射都有一个与之相关联的类型的值,预定义设置的类型有如下几种:Type name | Alias |
---|---|
bool | uint8_t |
int16_t | short |
int32_t | int |
int64_t | long, long long |
double | float |
long double | . |
string | . |
vector bool | vector uint8_t |
vector int16_t | vector short |
vector int32_t | vector int |
vector int64_t | vector long, vector long long |
vector double | vector float |
vector long double | . |
vector string | . |
python::object | object |
可以对于每一个映射类型通过调用new_vertex_property(),new_edge_property()或new_graph_property()为一个指定的图创建新的属性映射。
然后可以通过顶点或边的描述符或图本身来访问该值,因此:from itertools import izipfrom numpy.random import randintg = Graph()g.add_vertex(100)# insert some random linksfor s,t in izip(randint(0, 100, 100), randint(0, 100, 100)): g.add_edge(g.vertex(s), g.vertex(t))vprop_double = g.new_vertex_property("double") # Double-precision floating pointvprop_double[g.vertex(10)] = 3.1416vprop_vint = g.new_vertex_property("vector ") # Vector of intsvprop_vint[g.vertex(40)] = [1, 3, 42, 54]eprop_dict = g.new_edge_property("object") # Arbitrary python object.eprop_dict[g.edges().next()] = {"foo": "bar", "gnu": 42} # In this case, a dict.gprop_bool = g.new_graph_property("bool") # Booleangprop_bool[g] = True
标量值类型的属性映射也可以被当做numpy.ndarray来访问,通过get_array()方法,或者a属性。
from numpy.random import random# this assigns random values to the vertex propertiesvprop_double.get_array()[:] = random(g.num_vertices())# or more conveniently (this is equivalent to the above)vprop_double.a = random(g.num_vertices())
内部属性映射
任何创建的属性映射可以作为“内部”到相应的图上。
这意味着它将被复制并和图一起被保存到一个文件。 属性被内在化,通过将它们包括在图的类字典属性中:vertex_properties,edge_properties或graph_properties(或它们的别名,vp,ep或gp)。 当插入到图中时,属性映射必须有一个唯一的名称(相同类型的之间):>>> eprop = g.new_edge_property("string")>>> g.edge_properties["some name"] = eprop>>> g.list_properties()some name (edge) (type: string)
内部图的属性映射表现得略有不同。
它不是返回属性映射对象,值本身是从字典中返回的:>>> gprop = g.new_graph_property("int")>>> g.graph_properties["foo"] = gprop # this sets the actual property map>>> g.graph_properties["foo"] = 42 # this sets its value>>> print(g.graph_properties["foo"])42>>> del g.graph_properties["foo"] # the property map entry is deleted from the dictionary
为了方便起见,内部属性映射也可以通过属性来访问:
>>> vprop = g.new_vertex_property("double")>>> g.vp.foo = vprop # equivalent to g.vertex_properties["foo"] = vprop>>> v = g.vertex(0)>>> g.vp.foo[v] = 3.14>>> print(g.vp.foo[v])3.14
图的I/O
图可以通过四种格式保存和加载:graphml、dot、gml和一个定制的二进制格式gt(见gt文件格式)。
警告:
二进制格式gt和graphml是首选的格式,因为它们是迄今为止最完整的。
这些格式都是同样完整的,但gt速度更快,需要的存储空间也更少。
图可以保存或加载到一个文件上,通过save和load方法,以一个文件名或类似文件的对象。
图也可以从光盘上加载,通过load_graph()函数,如下:g = Graph()# ... fill the graph ...g.save("my_graph.xml.gz")g2 = load_graph("my_graph.xml.gz")# g and g2 should be copies of each other
图类也可以通过pickle模块来pickled with。
一个例子:构建一个 Price网络
Price网络是第一个已知的“无尺度”图模型,于1976年被de Solla Price发明。
它是被动态定义的,每一步添加一个新的顶点到图中,并连接到一个旧的顶点,概率与它的入度成正比。 下面的程序使用graph-tool实现了这个结构。注意:
只使用price_network()函数将会快得多,因为它是以c++实现的,而不是像下面的脚本一样使用纯python。
下面的代码仅仅是一个如何使用该库的示例。
#! /usr/bin/env python# We will need some things from several placesfrom __future__ import division, absolute_import, print_functionimport sysif sys.version_info < (3,): range = xrangeimport osfrom pylab import * # for plottingfrom numpy.random import * # for random samplingseed(42)# We need to import the graph_tool module itselffrom graph_tool.all import *# let's construct a Price network (the one that existed before Barabasi). It is# a directed network, with preferential attachment. The algorithm below is# very naive, and a bit slow, but quite simple.# We start with an empty, directed graphg = Graph()# We want also to keep the age information for each vertex and edge. For that# let's create some property mapsv_age = g.new_vertex_property("int")e_age = g.new_edge_property("int")# The final size of the networkN = 100000# We have to start with one vertexv = g.add_vertex()v_age[v] = 0# we will keep a list of the vertices. The number of times a vertex is in this# list will give the probability of it being selected.vlist = [v]# let's now add the new edges and verticesfor i in range(1, N): # create our new vertex v = g.add_vertex() v_age[v] = i # we need to sample a new vertex to be the target, based on its in-degree + # 1. For that, we simply randomly sample it from vlist. i = randint(0, len(vlist)) target = vlist[i] # add edge e = g.add_edge(v, target) e_age[e] = i # put v and target in the list vlist.append(target) vlist.append(v)# now we have a graph!# let's do a random walk on the graph and print the age of the vertices we find,# just for fun.v = g.vertex(randint(0, g.num_vertices()))while True: print("vertex:", int(v), "in-degree:", v.in_degree(), "out-degree:", v.out_degree(), "age:", v_age[v]) if v.out_degree() == 0: print("Nowhere else to go... We found the main hub!") break n_list = [] for w in v.out_neighbours(): n_list.append(w) v = n_list[randint(0, len(n_list))]# let's save our graph for posterity. We want to save the age properties as# well... To do this, they must become "internal" properties:g.vertex_properties["age"] = v_ageg.edge_properties["age"] = e_age# now we can save itg.save("price.xml.gz")# Let's plot its in-degree distributionin_hist = vertex_hist(g, "in")y = in_hist[0]err = sqrt(in_hist[0])err[err >= y] = y[err >= y] - 1e-2figure(figsize=(6,4))errorbar(in_hist[1][:-1], in_hist[0], fmt="o", yerr=err, label="in")gca().set_yscale("log")gca().set_xscale("log")gca().set_ylim(1e-1, 1e5)gca().set_xlim(0.8, 1e3)subplots_adjust(left=0.2, bottom=0.2)xlabel("$k_{in}$")ylabel("$NP(k_{in})$")tight_layout()savefig("price-deg-dist.pdf")savefig("price-deg-dist.png")
下面是程序的运行结果:
vertex: 36063 in-degree: 0 out-degree: 1 age: 36063vertex: 9075 in-degree: 4 out-degree: 1 age: 9075vertex: 5967 in-degree: 3 out-degree: 1 age: 5967vertex: 1113 in-degree: 7 out-degree: 1 age: 1113vertex: 25 in-degree: 84 out-degree: 1 age: 25vertex: 10 in-degree: 541 out-degree: 1 age: 10vertex: 5 in-degree: 140 out-degree: 1 age: 5vertex: 2 in-degree: 459 out-degree: 1 age: 2vertex: 1 in-degree: 520 out-degree: 1 age: 1vertex: 0 in-degree: 210 out-degree: 0 age: 0Nowhere else to go... We found the main hub!
下面是100000个节点的度的分布。
如果你想看到一个更广泛的幂律,可以尝试增加顶点的数量到(10 ^ 6)或(10 ^ 7)。 (10 ^ 5)个节点的Price网络的入度分布。 我们可以画图来观察它的一些其他的拓扑特性。 为此,我们可以使用graph_draw()函数。g = load_graph("price.xml.gz")age = g.vertex_properties["age"]pos = sfdp_layout(g)graph_draw(g, pos, output_size=(1000, 1000), vertex_color=[1,1,1,0], vertex_fill_color=age, vertex_size=1, edge_pen_width=1.2, vcmap=matplotlib.cm.gist_heat_r, output="price.png")
一个有(10 ^ 5 )个节点的Price网络。
顶点颜色代表顶点的年龄,旧的(红色),新的(黑)。原文链接: