2012-09-11 57 views
0

我有一個腳本,我計算:優化一個簡單的數學計算在列表

def sumsquared(arr): 
    sum = 0 
    idx = 0 
    len = arr.__len__() 
    while idx < (len - 1): 
      sum = sum + (arr[idx] * arr[idx]) + (arr[idx+1] * arr[idx+1]) 
      idx = idx + 2 

    return sum 

上述函數被調用一個循環填充兩個列表和兩次調用這個函數:第一次用列表len〜1024項,第二次使用len〜44100項。根據輸入,循環本身可以運行100到100000次。

對於小尺寸輸入,cProfile基於分析告訴我:

ncalls tottime percall cumtime percall filename:lineno(function) 
--------------------------------------------------------------------- 
2560 12.065 0.005 12.065 0.005 beat.py:8(sumsquared) 

這是總運行時間爲腳本約95%。有什麼方法可以加快這個功能嗎?

+3

你應該能夠使用LEN = LEN(ARR),無需調用.__ LEN __() – monkut

+0

@monkut,將無法工作,因爲'len'是函數中的一個局部變量,它會阻止訪問內建的'len()'。 WeaklyTyped應該能夠執行'length = len(arr)' – Duncan

+0

是的,或者只是使用len(arr)本身,而不是創建一個變量。 – monkut

回答

2

這是最快的,我可以找到

from itertools import imap 
from operator import mul 
def sumsquared(arr): 
    return sum(imap(mul, arr, arr)) 
5

你的功能很奇怪。它所要做的就是計算元素的平方和,但是如果有奇數個元素,則拋出最後一個元素。您由於某種原因一次添加兩個,但這不會影響最終結果。

爲了使速度更快,您可以使用numpy而不是編寫自己的函數。

>>> x = np.array([1, 2, 3, 4, 5]) 
>>> sumsquared(x) 
30 
>>> (x[:2*(len(x)//2)]**2).sum() 
30 

在一般情況下,如果你有一個數字的列表數千,使用numpy的陣列,而不是可能帶來重大的性能增益。

+1

轉換成numpy數組和從numpy數組轉換很昂貴。如果你一起做了一堆操作,它通常是有意義的。 –

+0

@gnibbler:的確如此,但這就是爲什麼我在最後添加了這一點。如果你有44000個數字的列表,你應該從頭開始使用numpy數組。 – BrenBarn

4

這看起來像對itertools module工作:

def sumsquared(arr): 
    s = sum(itertools.imap(operator.mul, arr, arr)) 
    return s - arr[-1] ** 2 if len(arr) & 1 else s 

使用總和運營商itertools將消除幾乎所有的純Python開銷。

另外,總和已被優化以在輸入爲輸入,浮點或兩者的某種組合時以接近C的速度運行。它可以累積運行總數而不用爲每個中間小計創建純粹的python對象。

來源:羅伯特金爲在必要時減去最後的廣場的想法。

另一個說明,如果您有興趣獲得高精度(即最小化精度損失),請考慮使用math.fsum而不是總和

+1

也許是這樣,但你可以更具體一點。 –

+0

'pairwise'返回'(s0,s1),(s1,s2)',問題要求'(s0,s1),(s2,s3)'。 –

1
sum([i**2 for i in arr]) - (arr[-1]**2 if len(arr) % 2 else 0) 
+0

你應該真的做'總結(我**在我的arr)'而不是。您的方法將計算整個列表,然後遍歷該列表以對元素進行求和。我建議使用生成器理解而不是列表理解。在我的測試中,生成器理解將運行時間減少到幾乎50%的OP算法 – inspectorG4dget

+0

guido今天說:「我正在使用生成器[表達式],除非你知道你有大量的值來迭代。在內存分配變得至關重要之前,列表[理解]通常比genexpr更快。「 - https://plus.google.com/s/guido –