给出无标度图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来表示图形,我发现的只是删除或添加特定边缘的过程。知道如何实现上述内容?
答案 0 :(得分:1)
虽然你已经接受了@ 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]
但老实说,我并不完全确定;它不再是我链接到上面的随机模型...
希望它无论如何都有帮助。
评论后更新
实际上,通过使用此方法将节点添加到现有图表,您可能会得到2个不希望的结果:
你可以删除它们,但它会使结果偏离预期的分布。
无论如何,你应该考虑到你已经偏离了优先附件模型,因为Barabasi-Albert研究的算法可以添加新的节点和现有图的链接,
网络以m_0个节点的初始连接网络开始。 新节点一次添加到网络中。每个新节点连接到m> m_0现有节点的概率与数量成正比 ...
(见here)
如果你想得到一个确切的分布(而不是增长一个现有的网络并保持其属性),你可能会更好地得到@joel的答案
希望它有所帮助。
答案 1 :(得分:1)
这里有2个算法:
算法1
此算法不会完全保留度数,而是保留预期的度数。
保存每个节点的初始学位。然后随机删除边缘。无论何时创建边缘,都要通过随机选择两个节点来实现,每个节点的概率与这些节点的初始程度成正比。
经过很长一段时间,每个节点的预期程度' u'是它的初始程度(但它可能会更高或更低)。
基本上,这将创建所谓的Chung-Lu随机图。 Networkx有一个用于创建它们的内置算法。
注意 - 这将允许学位分布变化。
算法1a
以下是有效的networkx实现,跳过删除和添加直接到最终结果的程度(假设有一个networkx图G
):
degree_list = G.degree().values()
H = nx.expected_degree_graph(degree_list)
算法2
此算法严格保留度数。
选择一组边并将其分开。创建一个列表,每个节点看起来都等于它所在的断边数。随机播放此列表。在此列表中彼此相邻的节点之间创建新边。
检查以确保您永远不会将节点加入自身或已经是邻居的节点。如果发生这种情况,您会想到一种自定义的方法来避免它。一种选择是简单地重新洗牌。另一种方法是将这些节点放在一边,并将它们包含在下次执行此列表时创建的列表中。
修改强>
内置的networkx命令double_edge_swap
一次交换两条边。 documentation
答案 2 :(得分:0)
我不确定这将在多大程度上保留无标度财产,但这可以是实现您的想法的一种方式:
为了添加边缘,您需要在networkx中指定2个节点。因此,您可以选择一个节点,其概率与(度)成比例,另一个节点统一选择(没有任何首选项)。选择高度连接的节点可以通过以下方式实现:
对于图G,其中节点为[0,1,2,...,n]
1)创建0到1之间的浮点数(限制)列表,以便为每个节点指定根据其度数^ 2选择的概率。例如:limits [1] - limits [0]是选择节点0的概率,limit [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 /度)而不是度数选择节点,然后统一删除任何边缘。
有趣的是,知道使用这种方法是否会保留无标度属性以及“C&#39;财产遗失了,所以请告诉我们是否有效。
编辑:正如@joel所建议的那样,选择添加边的节点应该与度数成比例而不是度数^ 2。我已相应地编辑了第1步。
EDIT2:这可能有助于您判断在添加和删除边缘后,无标度图是否会丢失其属性。只需在更改前后计算优先附件得分。你可以找到doumentation here。