扰动后保持无标度图的度分布 - python

Keeping scale free graph's degree distribution after perturbation - python

给定无标度图G(度分布为幂律的图),以及以下过程:

for i in range(C):
    coint = randint(0,1)
    if (coint == 0):
        delete_random_edges(G)
    else:
        add_random_edge(G)

(C为常数)
因此,当 C 较大时,程序后的度分布将更像 G(n,p)。我对保留幂律分布感兴趣,即 - 我希望图形在此过程后无标度,即使对于大 C。

我的想法是编写程序 "delete_random_edges" 和 "add_random_edge" 的方式可以让连接到节点的边被删除的概率小(添加新边时,添加新边的可能性更大)到度数大的节点)。

我使用 Networkx 来表示图形,我发现的只是删除或添加特定边的过程。知道如何实现上述内容吗?

我不确定这将在多大程度上保持自由尺度 属性 但这可以成为实现您的想法的一种方式:

In order to add an edge you need to specify 2 nodes in networkx. so, you can choose one node with a probability that is proportional to (degree) and the other node to be uniformly chosen (without any preferences). Choosing a highly connected node can be achieved as follows:

对于节点为 [0,1,2,...,n] 的图 G

1) 创建一个介于 0 和 1 之间的浮点数(限制)列表,以根据每个节点的度数 ^2 为每个节点指定要选择的概率。例如:limits[1] - limits[0]是选择节点0的概率,limits[2] - limits[1]是选择节点2的概率等

# limits is a list that stores floats between 0 and 1 which defines
# the probabaility of choosing a certain node depending on its degree
limits = [0.0]
# store total number of edges of the graph; the summation of all degrees is 2*num_edges
num_edges = G.number_of_edges()
# store the degree of all nodes in a list
degrees = G.degree()
# iterate nodes to calculate limits depending on degree
for i in G:
    limits.append(G.degree(i)/(2*num_edges) + limits[i])

2) 随机生成一个0到1之间的数,然后与极限进行比较,并相应地选择要添加边的节点:

rnd = np.random.random()
# compare the random number to the limits and choose node accordingly
for j in range(len(limits) - 1):
    if rnd >= limits[j] and rnd < limits[j+1]:
         chosen_node = G.node[j]

3) 统一选择另一个节点,生成一个介于[0,n]

之间的随机整数

4) 在两个选定节点之间添加一条边。

5) 同理删除边,可以根据(1/degree)而不是度选择一个节点,然后统一删除它的任意一条边。

It is interesting to know if using this approach would reserve the scale free property and at which 'C' the property is lost , so let us know if it worked or not.

编辑:正如@joel 所建议的,要添加边的节点的选择应该与度数而不是度数^2 成正比。我已经相应地编辑了第 1 步。

EDIT2:这可能会帮助您判断无标度图在添加和删除边后是否丢失了 属性。只需计算更改前后的优先attachmet分数。您可以找到证明 here.

虽然您已经接受了@abdallah-sobehy 的回答,这意味着它有效,但我建议采用更简单的方法,以防它对您或周围的任何人有所帮助。

您尝试做的有时称为优先依附(好吧,至少在您添加节点时是这样),为此有一个很久以前开发的随机模型,请参阅 Barabasi-Albert model,这导致gamma 的幂律分布等于 -3.

基本上,您必须添加边,其概率等于节点的度数除以所有节点的度数之和。您可以 scipy.stats 使用这样的代码来定义概率分布,

import scipy.stats as stats
x = Gx.nodes()
sum_degrees = sum(list(Gx.degree(Gx).values()))
p = [Gx.degree(x)/sum_degrees for x in Gx]
custm = stats.rv_discrete(name='custm', values=(x, p))

然后你只需选择遵循该分布的 2 个节点,这就是你添加边的 2 个节点,

custm.rvs(size=2)

至于删除节点,我自己没试过。但我想你可以使用这样的东西,

sum_inv_degrees = sum([1/ x for x in list(Gx.degree(Gx).values())])
p = [1 / (Gx.degree(x) * sum_inv_degrees) for x in Gx]

虽然老实说我不太确定;它不再是我 link 以上的随机模型...

希望对您有所帮助。

评论后更新

实际上,通过使用此方法向现有图形添加节点,您可能会得到 2 个不希望的结果:

  • 重复 links
  • 自己links

您可以删除它们,尽管这会使结果偏离预期分布。

无论如何,您应该考虑到您已经偏离了优先依附模型,因为 Barabasi-Albert 研究的算法可以向现有图表添加新节点和 links,

The network begins with an initial connected network of m_0 nodes. New nodes are added to the network one at a time. Each new node is connected to m > m_0 existing nodes with a probability that is proportional to the number ...

(参见 here

如果您想获得精确的分布(而不是发展现有网络并保持其属性),您最好使用@joel

的答案

希望对您有所帮助。

这里有 2 个算法:

算法一

此算法并未准确保留度数,而是保留了预期度数。

保存每个节点的初始度。然后随机删除边。每当你创建边时,通过随机选择两个节点来实现,每个节点的概率与这些节点的初始度成正比。

经过很长一段时间后,每个节点的期望度数'u'就是它的初始度数(但可能会高一点或低一点)。

基本上,这将创建所谓的 Chung-Lu 随机图。 Networkx 有一个用于创建它们的内置算法。

注意 - 这将允许学位分布发生变化。

算法 1a

这是高效的 networkx 实现,跳过度数删除和添加并直接进入最终结果(假设 networkx 图 G):

degree_list = G.degree().values()
H = nx.expected_degree_graph(degree_list)

这是documentation

算法2

该算法准确地保留了度数。

选择一组边并打断它们。创建一个列表,每个节点出现的次数等于它所在的断边数。打乱这个列表。在该列表中彼此相邻的节点之间创建新边。

检查以确保您永远不会将节点加入到自身或已经是邻居的节点中。如果发生这种情况,您将需要考虑一种自定义方法来避免它。一种选择是简单地重新排列列表。另一种方法是将这些节点放在一边,并将它们包含在您下次执行此操作时创建的列表中。

编辑 有一个内置的 networkx 命令 double_edge_swap 可以一次交换两条边。 documentation