簡體   English   中英

NetworkX - 生成隨機連接的二分圖

[英]NetworkX - generating a random connected bipartite graph

我正在使用NetworkX使用nx.bipartite.random_graphnx.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_graph(5,6,0.6)並且p>0.5可以消除錯誤。 類似地, bipartite.gnmk_random_graph(5,6,11)其中k>n+m 我沒有意識到這種情況,因為我假設如果邊緣的數量低於連接每個頂點所需的邊數,那么就會有一些浮動頂點。

謝謝你的幫助!

考慮到你有一個只有10個邊的{5,6}二分圖,很可能你的圖將被斷開(它很稀疏,你甚至很可能有孤立的節點)。

import networkx as nx
import random

random.seed(0)

B = nx.bipartite.gnmk_random_graph(5,6,10)
isolated_nodes = set(B.nodes())
for (u, v) in B.edges():
  isolated_nodes -= {u}
  isolated_nodes -= {v}
print(isolated_nodes)

將顯示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個參數)。

編輯我很蠢,這可能不行,因為新圖形沒有正確數量的節點/邊緣。 但是應該有一個更好的解決方案,而不僅僅是重試,直到你得到一個好的圖表。 嗯這很有趣......

第2次編輯也許這個答案可以幫助找到解決這個問題的好方法。

第3次編輯和建議

正如您在我鏈接的問題中所注意到的那樣,接受的答案並不十分正確,因為生成的圖形在預期圖形集中未隨機均勻選擇。 我們可以做一些類似的事情來獲得第一個合適的解決方案。 我們的想法是首先通過迭代選擇孤立節點並將它們連接到二分圖的另一側來創建具有最小邊數的連通二分圖。 為此,我們將創建兩組NM ,創建從NM的第一條邊。 然后我們將選擇一個隨機隔離節點(來自NM )並將其連接到另一側的隨機非隔離節點。 一旦我們沒有任何更多的孤立節點,我們就會有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)

但我再說一遍, 這個圖不是在所有可能的二分圖集中隨機均勻選擇的 (我們在n,m和k上定義了約束)。 正如我在另一篇文章中所說,這個圖表往往會有一些比其他節點更高的節點。 這是因為我們將隔離的節點逐個連接到連接的組件,因此在過程中更快添加的節點將傾向於吸引更多節點(優先連接)。 我問了關於cstheory問題 ,看看是否有任何好主意。

編輯我添加了另一個解決方案而不是這里提供的解決方案,它有點好但仍然不是一個好的解決方案。

簡短的回答

你想做

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]

說明

因此,當您生成此二分圖時,可能會斷開連接。 假設它有兩個獨立的組件XY 這兩個組件都是二分的。

bipartite.sets(B)應該確定哪些集合是B的兩個分區。 但它會遇到麻煩。

為什么?

X可以分為兩個分區X_1X_2Y可以分為Y_1Y_2 B怎么樣? top = X_1 + Y_1bottom = X_2 + Y_2 這是一個完全合法的分區。 top = X_1+Y_2bottom = X_2+Y_1也是完全合法的分區。 應該歸還哪一個? 這是模棱兩可的。 該算法明確拒絕做出選擇。 相反,它會給你一個錯誤。

該怎么辦? 如果斷開連接,你可以扔掉B ,然后再試一次。 但是你正在使用B做對嗎? 將注意力僅限於連接的圖表是否合理? 也許,也許不是。 這是你需要弄清楚的事情。 但是,如果原因是斷開連接的圖形不方便,那么將注意力僅限於連接的圖形是不合理的。 你似乎經常會遇到這個錯誤,所以很大一部分圖表都是斷開連接的 - 你扔掉了很大一部分案例。 看來這很可能會影響你所做的一切的最終結果。 (同樣地,如果你采取措施連接你的網絡,你就不再從原始發行版獲得隨機圖表,因為你已經確保它們沒有斷開連接,現在更糟糕的是 - 你可能不會從連通圖)。

那么什么是更好的選擇呢? 在查看源代碼之后,我發現這個方法沒有記錄,應該是這樣。 事實證明,那是為了

B = bipartite.gnmk_random_graph(5,6,10)

節點04 (前五個)位於頂部,節點510 (接下來的6個)位於底部。

或者,您可以直接從圖B編碼的數據中獲取它(文檔中未提及)。 嘗試

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]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM