2012-06-27 51 views
2

我正試圖在Python中完成以下邏輯操作,但是會陷入內存和時間問題。因爲,我對Python非常陌生,所以我將不勝感激關於如何以及在哪裏優化問題的指導! (我不明白以下問題有點抽象)如何在python中優化以下算法的內存和時間使用率

import networkx as nx 
    dic_score = {} 
    G = nx.watts_strogatz_graph(10000,10,.01) # Generate 2 graphs with 10,000 nodes using Networkx 
    H = nx.watts_strogatz_graph(10000,10,.01) 
    for Gnodes in G.nodes() 
     for Hnodes in H.nodes() # i.e. For all the pair of nodes in both the graphs 
      score = SomeOperation on (Gnodes,Hnodes) # Calculate a metric 
      dic_score.setdefault(Gnodes,[]).append([Hnodes, score, -1 ]) # Store the metric in the form a Key: value, where value become a list of lists, pair in a dictionary 

然後根據這裏提到的標準排序名單中產生的字典 sorting_criterion

我的問題/問題是:

1 )有沒有比使用for循環迭代更好的方法?

2)什麼應該是接近上述問題最優化(最快)的方法?我應該考慮使用另一種數據結構而不是字典嗎?或可能的文件操作? 3)由於我需要對字典中的列表進行排序,該列表中有10,000個鍵,每個鍵對應一個10,000個值的列表,所以內存需求變得非常快,而且我用完了。

3)有沒有一種方法可以將排序過程集成到字典本身的計算中,即避免做一個單獨的循環來排序?

任何輸入將不勝感激!謝謝 !

+0

10^4×10^4個節點= 10^8。當然這很慢。沒有你想要做的事情的信息,運行時間和內存使用情況很難改善。 – nhahtdh

+0

@nhahtdh:基本上,循環代表提取與每個節點相關的向量。我很感興趣的是從這兩個圖形即所有可能的這些向量對的點積,即10000 * 10000對。因此,每個節點都將與10000個這樣的點積相關聯,然後我想對它們進行排序並保存以供進一步處理。正如您正確地提到的那樣,計算時間非常巨大,內存需求也是如此,我希望通過一些文件操作或任何其他建議來優化內存需求。 –

回答

5

1)你可以使用一個的功能從itertools模塊。讓我提到它,你可以閱讀手冊,或致電:

from itertools import product 
help(product) 

下面是一個例子:

for item1, item2 in product(list1, list2): 
    pass 

2)如果結果是太大,不適合在內存中,儘量爲他們節省地方。您可以將其輸出到CSV文件中,例如:

with open('result.csv') as outfile: 
    writer = csv.writer(outfile, dialect='excel') 
    for ... 
     writer.write(...) 

這會釋放您的記憶。 3)我認爲最好是事後對結果數據進行排序(因爲sort函數相當快),而不是使事情複雜化並對數據進行即時排序。

您可以改爲使用NumPy arroy/matrix操作(總和,乘積,或者甚至將函數映射到每個矩陣行)。這些速度如此之快,以至於有時候過濾數據的成本遠遠超過計算所有內容。

如果你的應用程序仍然很慢,嘗試剖析它,看看到底是什麼操作慢或做太多次:

from cProfile import Profile 
p = Profile() 

p.runctx('my_function(args)', {'my_function': my_function, 'args': my_data}, {}) 
p.print_stats() 

你會看到表:

 2706 function calls (2004 primitive calls) in 4.504 CPU seconds 

Ordered by: standard name 

ncalls tottime percall cumtime percall filename:lineno(function) 
    2 0.006 0.003 0.953 0.477 pobject.py:75(save_objects) 
    43/3 0.533 0.012 0.749 0.250 pobject.py:99(evaluate) 
... 
+0

非常感謝您的詳細解答。讓我對你的反饋和觀察結果進行研究。 –

+1

NumPy數組也具有內存效率。 –

+0

@Janne Karila:我的意思是陣列,當然,謝謝。 –

4

當使用返回列表的函數時,請檢查返回迭代器的函數。

這將改善內存使用情況。

就你而言,nx.nodes返回完整列表。參見:nodes

使用nodes_iter因爲它返回一個迭代器。這應確保您在for循環中的節點上迭代時沒有內存中的完整節點列表。

參見:nodes_iter

一些改進:

import networkx as nx 
    dic_score = {} 
    G = nx.watts_strogatz_graph(10000,10,.01) 
    H = nx.watts_strogatz_graph(10000,10,.01) 
    for Gnodes in G.nodes_iter() ----------------> changed from G.nodes() 
     for Hnodes in H.nodes_iter() -----------> changed from H.nodes() 
      score = SomeOperation on (Gnodes,Hnodes) 
      dic_score.setdefault(Gnodes,[]).append([Hnodes, score, -1 ]) 

你也可以用其他的成語,因爲現在你有兩個迭代器:使用itertools.products

product(A, B) returns the same as ((x,y) for x in A for y in B). 
+0

這真的很有幫助!感謝您的見解。我正在嘗試實施您的所有建議。 –

1

其他人提到了itertools.product。這很好,但就你而言,還有另外一種可能性:內部循環的生成器表達式和函數sorted。 (當然,代碼未經測試)。

import networkx as nx 
from operator import itemgetter 
dic_score = {} 
G = nx.watts_strogatz_graph(10000,10,.01) # Generate 2 graphs with 10,000 nodes using Networkx 
H = nx.watts_strogatz_graph(10000,10,.01) 
for Gnodes in G.nodes(): 
    dic_score[Gnodes] = sorted([Hnodes, score(Gnodes, Hnodes), -1] for Hnodes in H.nodes(), key=operator.itemgetter(1)) # sort on score 

內部循環被生成器表達式替換。它也在飛行中排序(假設您想對score中的每個內部列表進行排序)。您可以輕鬆地將每個內部列表寫入文件,而不是將其存儲在字典中,這有助於記憶。

+0

感謝您的回答。我在這裏不確定,因爲我正在學習Python,但遇到了一個cPickle模塊。無論如何,每個內循環後都會使用它嗎? –

+0

如果內存是您的主要問題,您可以將結果寫入磁盤來替換'dic_score [Gnodes] = ...'。我對(c)泡菜幫不了你,但我認爲它會起作用。 – WolframH