2015-10-26 54 views
0

我是Python新手,正在使用NetworkX來構建圖形。迭代3個字典(關注速度)

在我的腳本我有三個字典這或許需要被嵌套在彼此內:

  1. dict1 = { '節點ID':1} - >dict1={'0':1,'1':1,'2':1, ...}
  2. dict2 = { '節點ID' :G.neighbors(節點ID)} - >dict2={'0':[1,2,4], ...}
  3. dict3 = { '節點ID':狀態} - >dict3={'1':1, '2':0, '4':1}

爲了一清二楚,dict1告訴我,如果該節點有效(1)或失敗(0)[在這種情況下,所有節點dict1都處於活動狀態]。 dict2包含連接到每個節點dict1的所有節點; dict3告訴我連接到dict1的每個節點的所有節點是活動(1)還是失敗(0)。

我的問題。我希望能夠建模節點之間的交互。這意味着如果節點0處於活動狀態(status=1)並且有3個節點連接到它,如果它們全都失敗(status=0),則節點0也會失敗。如果只有一個連接的節點仍處於活動狀態,則節點0仍然處於活動狀態。

我的企圖。這是理論上的流程我已經設想,但我不知道怎麼把它翻譯成Python,我也不知道這是不是最好的辦法:

  1. 遍歷dict1;
  2. 對於dict1的每個鍵,獲取與當前dict1鍵相關聯的dict2的值;
  3. 對於在dict2中找到的每個值,請檢查dict3它們的狀態是0還是1(在dict2中找到的值成爲dict3的關鍵字);
  4. 如果(且僅當)中的所有dict3鍵發現這種方式取0,改變與當前dict1鍵相關聯的值設置爲0

PS:該流程圖是將被施加到一個10000個節點的網絡,所以重點在於速度。嵌套3 for循環可能聽起來像一個(非常)糟糕的主意,所以我會很感激不同的解決方案。

我很抱歉無法將此代碼放入正確的代碼,但我非常掙扎。非常感謝!

+1

您不必在3個字符上循環,因爲它們可以直接訪問它們的值。你只需要在dict1鍵集中進行迭代。但是你的主要問題是你可以用一組對象做你想做的事情。 – JoshRomRock

+0

謝謝!你能爲我提供一個「實驗」嗎?我發現字典的地區充滿了可能的地雷...... – FaCoffee

+1

您是否嘗試設置一個節點類,其中包含字段node_id,鄰居(作爲節點列表)和狀態?把它們放在一個集合中,然後遍歷它來應用你的規則。備註:我不知道NetworkX,所以我不確定你想要的輸出。 – JoshRomRock

回答

1

正如意見建議的JoshRomRock,您可以創建這樣一個類:

class Node(object): 
    def __init__(self, node_id, neighbours, status): 
     # neighbours could be a list of other Node objects 
     self.node_id = node_id 
     self.neighbours = neighbours 
     self.status = status 

    def neighbours_status(self): 
     # this method would return a list of tuples, 
     # where first tuple elem is node_id and the second is its status 
     return [(n.node_id, n.status) for n in self.neighbours] 

後來用它在你的代碼是這樣的:

my_nodes = set() # create set 
my_nodes.add(Node(0, [], 1)) # add a node with no neighbours 
# add some more nodes here ... 

for node in my_nodes: 
    # do something with node.status, or node.node_id, or node.neighbours_status() 
+0

謝謝。順便說一句,我不明白如何在我的情況下使用它。我不需要添加節點 - 我已經有了10000個節點。另外,你定義的'my_nodes = set()'是我從未見過的東西... – FaCoffee

+1

爲了使用類解決方案,你必須首先將節點的表示轉換爲這個節點,稍後你將受益於輕鬆遍歷的能力。它也比使用嵌套的'for'循環更快。這就是爲什麼我建議添加它們。至於'set',你可能想看看這裏:https://docs.python.org/2/library/sets.html – pzelasko

+0

有幾個問題:你將如何使用'Node'類?你會如何正確地稱呼它?這個班級需要什麼「對象」?它在三條線上做了什麼?我很抱歉,看起來很複雜... – FaCoffee

1

我覺得這可能是一個"X/Y"的問題。我不相信你試圖實現你的解決方案的方式是最好的,但我會盡力回答你提出的問題。你可能會問一個稍微寬泛一些的問題。

下面是什麼,我想您所描述的僞代碼:

initialize nodes 
create some initial set_of_nodes such that all have status active. 
for node in set_of_nodes: 
    if node has no neighbors: 
     move on 
    else: 
     has_active_neighbor = False 
     for neighbor in neighbors(node): 
      add neighbor to set_of_nodes 
      if neighbor's status is active: 
       has_active_neighbor = True 
     if has_active_neighbor = False: 
      node's status becomes inactive. 

沒有與此代碼中的一些潛在問題。您可能會在迭代時迭代並更改某些節點的狀態,這意味着如果您再次檢查了一些已經處理的節點將會失敗。所以你正在尋找某種級聯。您可能想要遍歷節點,直到不發生任何更改。另外,在循環播放時添加到集合中有點奇怪。這在Python(以及一般)中是一個不容忽視的問題。所以我創建了一組新的節點。所以根據你試圖學習的系統規則,這可能不是最好的。另外,我不明白你爲什麼從一個子集開始,而不是你的dict1的整個網絡。

這是networkx的實現。我將循環直到沒有發生變化。

import networkx as nx 

# code here to define graph, assign initial statuses, and create node_set 
# node attributes can be defined in several ways (one appears below) 

changes = True 
while changes: 
    changes = False 
    added_nodes = set() 
    for x in node_set: 
     if G.degree(x)==0 or G.node[x]['status'] == 'failed': 
      continue #nothing to see here, move on. 
     else: 
      has_active_neighbor=False 
      for neighbor in G.neighbors(x): 
       added_nodes.add(neighbor) #put it here even if it is already in node_set 
       if G.node[neighbor]['status'] == 'active': 
        has_active_neighbor = True 
        break 
      if not has_active_neighbor: 
       changes = True 
       G.node[x]['status'] = 'failed' 
    if node_set.difference(added_nodes): #True if any new nodes: 
     node_set = node_set.union(added_nodes) 
     changes = True 

#everything is done now - here's the dictionary of statuses: 
statuses = nx.get_node_attributes(G, 'status') 
+0

謝謝!我不認爲有關已經處理的節點的問題是一個真正的問題。我認爲我在這裏沒有足夠的空間來解釋,所以如果我們能夠把它變成聊天來給它適當的空間,我會很高興。我可能也會給你一些細節,你沒有指出。 – FaCoffee

+0

我對這個過程的期望是一個字典,其中關鍵字是節點ID,並且基於節點失敗或者失敗,值爲0或1。 – FaCoffee

+1

我相信我在最後添加的這一行提供了這一點。如果您想要0或1,請編輯代碼的相應部分。實際上,我認爲一個更好的名字是'G.node [x] ['active'] = True'(或'False'),然後有一個名爲'active'的字典,以便'active [node]'是「真」還是「假」。 – Joel