2017-05-10 60 views
7

我有一個計算項目,大量使用日誌功能(整數),數十億次調用。我發現numpy的日誌表現出奇的慢。numpy的日誌功能會發生什麼?有沒有方法提高性能?

下面的代碼需要15至17秒來完成:

import numpy as np 
import time 

t1 = time.time() 
for i in range(1,10000000): 
    np.log(i) 
t2 = time.time() 
print(t2 - t1) 

然而,math.log函數取從3到4秒的時間少得多。

import math 
import time 

t1 = time.time() 
for i in range(1,10000000): 
    math.log(i) 
t2 = time.time() 
print(t2 - t1) 

我還測試了matlab和C#,它分別需要約2秒和0.3秒。

MATLAB

tic 
for i = 1:10000000 
    log(i); 
end 
toc 

C#

var t = DateTime.Now; 
for (int i = 1; i < 10000000; ++i) 
    Math.Log(i); 
Console.WriteLine((DateTime.Now - t).TotalSeconds); 

是否有蟒蛇任何方式,我可以提高日誌功能的表現?

+0

我對這個答案很感興趣。特別是因爲我剛進入源代碼,並且該函數很難追蹤。在源代碼的左邊,它寫着:'#真實簽名未知;從__doc__'恢復。任何人都可以解釋源代碼的工作原理嗎? –

+1

答案似乎在這裏http://stackoverflow.com/questions/3650194/are-numpys-math-functions-faster-than-pythons?rq=1 – Bathsheba

+9

'np.log'經過優化,適用於數組值,而不是單個值。例如'np.log(np.arange(1,10000000))'(該範圍內的整數數組的日誌)對我來說大約需要120ms。 –

回答

2

NumPys函數是爲不是單值或標量的數組而設計的。它們的開銷相當高,因爲它們會進行多次檢查和轉換,這將爲大數組提供速度優勢,但這對標量是昂貴的。

>>> import numpy as np 
>>> import math 

>>> type(np.log(2.)) 
numpy.float64 
>>> type(math.log(2.)) 
float 

在另一方面math -module是標量優化:如果你檢查返回類型

轉換是真的很明顯。所以他們不需要那麼多的支票(我認爲只有兩個:轉換爲float,並檢查它是<= 0)。這就是爲什麼math.log更快爲爲標量numpy.log相比。

但是,如果你操作數組,並且想要取數組中所有元素的對數,NumPy可以快得多。在我的電腦,如果我比列表中的每個項目的math.log時間陣列上的np.log執行,則時間看起來不一樣:

arr = np.arange(1, 10000000) 
%timeit np.log(arr) 
201 ms ± 959 µs per loop (mean ± std. dev. of 7 runs, 1 loop each) 

lst = arr.tolist() 
%timeit [math.log(item) for item in lst] 
8.77 s ± 63.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) 

所以np.log將多個數量級的速度在陣列(它比在這種情況下快40倍)!你不需要自己寫任何循環。由於ufunc np.log也將在多維numpy數組上正確工作,並且允許在原地進行操作。

作爲一個經驗法則:如果你有一個數組有數千個項目NumPy會更快,如果你有標量或只有幾十項math +顯式循環會更快。


也不要使用time作爲時間碼。有專門的模塊,讓結果更準確,更好的統計數據和禁用垃圾收集定時期間:

我一般用%timeit這是圍繞timeit功能的便捷包裝,但它需要IPython。他們已經方便地顯示結果的均值和偏差,並做一些(大部分)有用的統計數據,如顯示「7的最佳」或「3的最好結果」。


我最近分析的numpy的功能運行時行爲another question,一些觀點也適用於此。

1

有趣的是,Python標準庫是慢我的機器上不復制的問題(WINDOWS 10,運行的Python 2.7.11和numpy的1.11.0)。

>>> t1 = time.time() 
>>> for i in range(1,10000000): 
>>>  _ = np.log(i) 
>>> t2 = time.time() 
>>> print(t2 - t1) 
9.86099982262 
>>> t1 = time.time() 
>>> for i in range(1,10000000): 
>>>  _ = math.log(i) 
>>> t2 = time.time() 
>>> print(t2 - t1) 
2.48300004005 

與您在Matlab中的表現類似。 @Nils提供了一個很好的觀點,numpy被設計爲在數組上效率很高。

>>> t1 = time.time() 
>>> for i in range(1,1000): 
>>>  _ = np.log(np.arange(1,10000)) 
>>> t2 = time.time() 
>>> print(t2 - t1) 
0.146000146866 
>>> t1 = time.time() 
>>> for i in range(1,1000): 
>>>  _ = [math.log(i) for i in range(1,10000)] 
>>> t2 = time.time() 
>>> print(t2 - t1) 
2.3220000267 

如果你可以矢量化你的輸入,numpy將會勝過標準的數學庫,甚至會接近C#。

相關問題