2015-07-11 29 views
3

這是我對代碼的第一次優化,我很興奮。閱讀一些文章,但我仍然有一些問題。在Python中使用pstats和cProfile。如何使陣列工作更快?

1)首先,下面我的代碼花了那麼多時間?我認爲這是數組在這裏:array.append(len(set(line.split())))。我在網上閱讀,Python中的列表工作得更快,但我沒有看到在這裏使用列表。有人知道如何改進?

2)有沒有其他改進我失蹤?

3)另外,網上說它for循環減慢代碼很多。這裏可以改進嗎? (我猜在C編寫的代碼是最好的,但是:D)

4)爲什麼人們建議總是看「ncalls」和「tottime」?對我而言,「percall」更有意義。它告訴你你的功能或通話有多快。

5)在這裏的正確答案B類他申請名單。他呢?對我來說,我仍然可以看到一個數組和一個FOR循環,它可以減慢速度。 Fastest way to grow a numpy numeric array

謝謝。

NEW CPROFILE結果:

618384 function calls in 9.966 seconds 

    Ordered by: internal time 

    ncalls tottime percall cumtime percall filename:lineno(function) 
    19686 3.927 0.000 4.897 0.000 <ipython-input-120-d8351bb3dd17>:14(f) 
    78744 3.797 0.000 3.797 0.000 {numpy.core.multiarray.array} 
    19686 0.948 0.000 0.948 0.000 {range} 
    19686 0.252 0.000 0.252 0.000 {method 'partition' of 'numpy.ndarray' objects} 
    19686 0.134 0.000 0.930 0.000 function_base.py:2896(_median) 
     1 0.126 0.126 9.965 9.965 <ipython-input-120-d8351bb3dd17>:22(<module>) 
    19686 0.125 0.000 0.351 0.000 _methods.py:53(_mean) 
    19686 0.120 0.000 0.120 0.000 {method 'reduce' of 'numpy.ufunc' objects} 
    19686 0.094 0.000 4.793 0.000 function_base.py:2747(_ureduce) 
    19686 0.071 0.000 0.071 0.000 {method 'flatten' of 'numpy.ndarray' objects} 
    19686 0.065 0.000 0.065 0.000 {method 'format' of 'str' objects} 
    78744 0.055 0.000 3.852 0.000 numeric.py:464(asanyarray) 

NEW CODE:

import numpy 
import cProfile 

pr = cProfile.Profile() 
pr.enable() 

#paths to files 
read_path = '../tweet_input/tweets.txt' 
write_path = "../tweet_output/ft2.txt" 


def f(a): 
    for i in range(0, len(array)): 
     if a <= array[i]: 
      array.insert(i, a) 
      break 
    if 0 == len(array): 
     array.append(a) 

try: 
    with open(read_path) as inf, open(write_path, 'a') as outf: 
     array = [] 
     #for every line (tweet) in the file 
     for line in inf:           ###Loop is bad. Builtin function is good 
      #append amount of unique words to the array 
      wordCount = len(set(line.split())) 
      #print wordCount, array 
      f(wordCount) 
      #write current median of the array to the file 
      result = "{:.2f}\n".format(numpy.median(array)) 
      outf.write(result) 
except IOError as e: 
    print 'Operation failed: %s' % e.strerror 


###Service 
pr.disable() 
pr.print_stats(sort = 'time') 

OLD CPROFILE結果:在13.195秒 由有序 551211函數調用:內部時刻
ncalls tottime percall cumtime percall文件名:lineno(功能) 78744 10.193 0.0 00 10.193 0.000 {numpy.core.multiarray.array}

OLD CODE:

with open(read_path) as inf, open(write_path, 'a') as outf: 
     array = [] 
     #for every line in the file 
     for line in inf:        
      #append amount of unique words to the array 
      array.append(len(set(line.split()))) 
      #write current median of the array to the file 
      result = "{:.2f}\n".format(numpy.median(array)) 
      outf.write(result) 

回答

1

numpy的使用meadian finding algorithm即是O(n log n)的。你每行調用numpy.meadian一次,所以你的算法最終是O(n^2 log n)。

有幾種方法可以對此進行改進。一種是保持數組排序(即將每個元素插入維護排序順序的位置)。每個插入操作需要O(n)(插入到數組中是一個線性時間操作),並且獲得一個有序數組的中位數爲O(1),所以這最終爲O(n^2)。

對於性能分析,您要查看的主要內容是tottime,因爲這會告訴您程序花費在函數上的時間總共多少。正如在你的例子中,percall有時不是很有用,因爲有時候,如果你有一個緩慢的功能(高percall),但它只被稱爲幾次(低numcalls),tottime結果是微不足道的其他功能。

+0

您是否基於cProfile輸出做出了這個結論?如果是的話,你怎麼看?這條線是唯一暗示爲什麼需要這麼長時間的「numpy.core.multiarray.array」。但它沒有提及任何有關中位數函數的內容。 – Sergey

+0

中位數函數是numpy庫的一部分。 cProfile中的{numpy.core.multiarray.array}是在numpy庫中花費在* everything *上的時間。我做出了結論,因爲你只有一次調用你的循環中的'numpy'庫函數 - 調用'numpy.median'。 您可以通過在新函數中將調用包裝爲'median'來查看,並在cProfile中查看在該函數中花費的'tottime'。 – James

+0

哼!很有意思。我在數組中實現了排序插入。現在運行代碼的總時間從11.873降至9.966。我會在上面發佈我的新解決方案。看起來我在{numpy.core.multiarray.array}上的代碼花費了3.797和9.309秒,但是我創建的函數又花了3.927秒。因此3.797 + 3.927 = 7.724秒。這是一樣的。難道我做錯了什麼? – Sergey