Python NetworkX-生成随机连通二部图
我正在使用NetworkX使用Python NetworkX-生成随机连通二部图,python,networkx,bipartite,Python,Networkx,Bipartite,我正在使用NetworkX使用nx.bipartite.random_graph或nx.bipartite.gnmk_random_graph生成一个二部图,如下所示: B = bipartite.gnmk_random_graph(5,6,10) bottom_nodes, top_nodes = bipartite.sets(B) 但是,我得到一个错误: networkx.exception.AmbiguousSolution: Disconnected graph: Ambiguous
nx.bipartite.random_graph
或nx.bipartite.gnmk_random_graph
生成一个二部图,如下所示:
B = bipartite.gnmk_random_graph(5,6,10)
bottom_nodes, top_nodes = bipartite.sets(B)
但是,我得到一个错误:
networkx.exception.AmbiguousSolution: Disconnected graph: Ambiguous solution for bipartite sets.
这只是一行,所以我不确定我怎么会做错,为什么他们的包会返回(我假设是)一个无效的二分图
谢谢
编辑:我刚刚意识到我需要为第三个参数指定最小边数/概率
例如,bipartite.random_图(5,6,0.6)
和p>0.5
可以消除错误。类似地,bipartite.gnmk_random_图(5,6,11)
其中k>n+m
。我没有意识到这种情况,因为我假设如果边的数量低于连接每个顶点所需的数量,那么只会有一些浮动顶点
谢谢你的帮助 考虑到一个只有10条边的{5,6}二部图,很可能图是断开连接的(它非常稀疏,甚至很可能有孤立节点) 将向您显示id为1的节点是隔离的。要使图形连接,您可以只保留其最大的连接组件:
import networkx as nx
import random
random.seed(0)
B = nx.bipartite.gnmk_random_graph(5,6,11)
components = sorted(nx.connected_components(B), key=len, reverse=True)
largest_component = components[0]
C = B.subgraph(largest_component)
这将仅删除节点1(孤立节点)
现在唯一的问题是“这个新图表有多随机”。换言之,它是否在具有5-6个节点和10条边且概率相等的随机连通二部图集中选择任何图。目前我还不确定,但我认为这看起来不错
当然,您的建议(选择一个图形直到其连接)是可以的,但它可能会很昂贵(当然取决于3个参数)
编辑我很笨,这不可能正常,因为新图形没有正确数量的节点/边。但是应该有一个更好的解决方案,而不是在得到一个好的图之前重试。嗯,那很有趣
第二次编辑也许这有助于找到解决此问题的好方法
第三次编辑和建议
正如您在我链接的问题中所注意到的,所接受的答案并不真正正确,因为生成的图不是在预期图集中随机均匀地选择的。我们可以做一些类似的事情来获得第一个像样的解决方案。其思想是首先通过迭代拾取孤立节点并将其连接到二部图的另一侧,创建一个边数最少的连通二部图。为此,我们将创建两组N
和M
,创建从N
到M
的第一条边。然后,我们将选择一个随机隔离节点(从N
或M
)并从另一侧将其连接到一个随机非隔离节点。一旦我们不再有任何孤立节点,我们将有n+m-1条边,因此我们需要向图中添加k-(n+m-1)条额外的边以匹配原始约束
下面是与该算法对应的代码
import networkx as nx
import random
random.seed(0)
def biased_random_connected_bipartite(n, m, k):
G = nx.Graph()
# These will be the two components of the bipartite graph
N = set(range(n))
M = set(range(n, n+m))
G.add_nodes_from(N)
G.add_nodes_from(M)
# Create a first random edge
u = random.choice(tuple(N))
v = random.choice(tuple(M))
G.add_edge(u, v)
isolated_N = set(N-{u})
isolated_M = set(M-{v})
while isolated_N and isolated_M:
# Pick any isolated node:
isolated_nodes = isolated_N|isolated_M
u = random.choice(tuple(isolated_nodes))
# And connected it to the existing connected graph:
if u in isolated_N:
v = random.choice(tuple(M-isolated_M))
G.add_edge(u, v)
isolated_N.remove(u)
else:
v = random.choice(tuple(N-isolated_N))
G.add_edge(u, v)
isolated_M.remove(u)
# Add missing edges
for i in range(k-len(G.edges())):
u = random.choice(tuple(N))
v = random.choice(tuple(M))
G.add_edge(u, v)
return G
B = biased_random_connected_bipartite(5, 6, 11)
但是我重复一遍,这个图不是在所有可能的二部图集合中随机选择的。正如我在另一篇文章中所说的,这个图将倾向于有一些节点的阶数高于其他节点。这是因为我们将孤立节点一个接一个地连接到连接的组件,因此在该过程中添加得更快的节点将倾向于吸引更多节点(优先连接)。我问他是否有什么好主意
编辑我添加了一个比这里介绍的解决方案更好的解决方案,但仍然不是一个好的解决方案 简短回答 你想做什么
B = bipartite.gnmk_random_graph(5,6,10)
top = [node for node in B.nodes() if B.node[node]['bipartite']==0]
bottom = [node for node in B.nodes() if B.node[node]['bipartite']==1]
解释 因此,当您生成这个二部图时,它很可能是断开连接的。假设它有两个独立的组件
X
和Y
。这两个组件都是二部的
bipartite.set(B)
应该确定哪些集合是B
的两个分区。但它会遇到麻烦的
为什么?
X
可分为两个分区X\u 1
和X\u 2
和Y
可分为Y\u 1
和Y\u 2
。那B
呢?让top=X_1+Y_1
和bottom=X_2+Y_2
。这是完全合法的分割。但是top=X_1+Y_2
和bottom=X_2+Y_1
也是一个完全合法的分区。它应该退回哪一个?这是模棱两可的。算法明确拒绝做出选择。相反,它会给你一个错误
怎么办?如果断开连接,您可以抛出
B
,然后重试。但是你在用B
做点什么,对吗?将注意力限制在连通图上是否合理?也许,也许不是。这是你需要弄清楚的。但是,如果原因是断开连接的图不方便,那么将注意力限制在连通图上是不合理的。你似乎经常碰到这个错误,所以大部分的图表都是断开连接的——你扔掉了大部分的案例。这似乎可能会影响你所做的一切的最终结果。(类似地,如果您采取步骤连接网络,您将不再从原始分发中获取随机图,因为您已经确保它们没有断开连接,更糟糕的是,您可能无法从连接的图中进行统一采样)
那么有什么更好的选择呢?在查看源代码之后,我发现这个方法没有得到应有的文档化。事实证明,这是因为
B = bipartite.gnmk_random_graph(5,6,10)
节点0
最多4
(前五个)位于顶部,节点5
最多10
(第五个)
B = bipartite.gnmk_random_graph(5,6,10)
B = bipartite.gnmk_random_graph(5,6,10)
B.nodes(data=True)
> NodeDataView({0: {'bipartite': 0}, 1: {'bipartite': 0}, 2: {'bipartite': 0}, 3: {'bipartite': 0}, 4: {'bipartite': 0}, 5: {'bipartite': 1}, 6: {'bipartite': 1}, 7: {'bipartite': 1}, 8: {'bipartite': 1}, 9: {'bipartite': 1}, 10: {'bipartite': 1}})
top = [node for node in B.nodes() if B.node[node]['bipartite']==0]
bottom = [node for node in B.nodes() if B.node[node]['bipartite']==1]