2016-05-26 18 views
5

今天我描述了一個函數,我發現了一個(至少對我來說)奇怪的瓶頸:用mask=Nonemask=0創建一個蒙版數組來初始化一個蒙版與所有零,但相同的形狀data很慢:爲什麼用mask = None或mask = 0創建一個非常緩慢的蒙版numpy數組

>>> import numpy as np 
>>> data = np.ones((100, 100, 100)) 

>>> %timeit ma_array = np.ma.array(data, mask=None, copy=False) 
1 loop, best of 3: 803 ms per loop 

>>> %timeit ma_array = np.ma.array(data, mask=0, copy=False) 
1 loop, best of 3: 807 ms per loop 

使用mask=False或手工創建的面具另一方面要快得多:

>>> %timeit ma_array = np.ma.array(data, mask=False, copy=False) 
1000 loops, best of 3: 438 µs per loop 

>>> %timeit ma_array = np.ma.array(data, mask=np.zeros(data.shape, dtype=bool), copy=False) 
1000 loops, best of 3: 453 µs per loop 

爲什麼給None0幾乎比Falsenp.zeros(data.shape)慢0123倍作爲mask參數?鑑於function docs只說明它:

必須可轉換爲與數據形狀相同的布爾值數組。 True表示蒙面(即無效)數據。

我使用Python 3.5,numpy的1.11.0在Windows 10

+0

你有沒有深入研究numpy代碼呢? –

回答

4

mask=False是特例,在NumPy 1.11.0 source code

if mask is True and mdtype == MaskType: 
    mask = np.ones(_data.shape, dtype=mdtype) 
elif mask is False and mdtype == MaskType: 
    mask = np.zeros(_data.shape, dtype=mdtype) 

mask=0mask=None走慢速通道,使得0〜三維蒙版陣列並通過np.resize來調整其大小。

+0

並且'resize'確實有'a = concatenate((a,)* n_copies)'。 – hpaulj

1

我相信@ user2357112有解釋。我分析了這兩種情況,結果如下:

In [14]: q.run('q.np.ma.array(q.data, mask=None, copy=False)') 
     49 function calls in 0.161 seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     3 0.000 0.000 0.000 0.000 :0(array) 
     1 0.154 0.154 0.154 0.154 :0(concatenate) 
     1 0.000 0.000 0.161 0.161 :0(exec) 
     11 0.000 0.000 0.000 0.000 :0(getattr) 
     1 0.000 0.000 0.000 0.000 :0(hasattr) 
     7 0.000 0.000 0.000 0.000 :0(isinstance) 
     1 0.000 0.000 0.000 0.000 :0(len) 
     1 0.000 0.000 0.000 0.000 :0(ravel) 
     1 0.000 0.000 0.000 0.000 :0(reduce) 
     1 0.000 0.000 0.000 0.000 :0(reshape) 
     1 0.000 0.000 0.000 0.000 :0(setprofile) 
     5 0.000 0.000 0.000 0.000 :0(update) 
     1 0.000 0.000 0.161 0.161 <string>:1(<module>) 
     1 0.000 0.000 0.161 0.161 core.py:2704(__new__) 
     1 0.000 0.000 0.000 0.000 core.py:2838(_update_from) 
     1 0.000 0.000 0.000 0.000 core.py:2864(__array_finalize__) 
     5 0.000 0.000 0.000 0.000 core.py:3264(__setattr__) 
     1 0.000 0.000 0.161 0.161 core.py:6119(array) 
     1 0.007 0.007 0.161 0.161 fromnumeric.py:1097(resize) 
     1 0.000 0.000 0.000 0.000 fromnumeric.py:128(reshape) 
     1 0.000 0.000 0.000 0.000 fromnumeric.py:1383(ravel) 
     1 0.000 0.000 0.000 0.000 numeric.py:484(asanyarray) 
     0 0.000    0.000   profile:0(profiler) 
     1 0.000 0.000 0.161 0.161 profile:0(q.np.ma.array(q.data, mask=None, copy=False)) 

In [15]: q.run('q.np.ma.array(q.data, mask=False, copy=False)') 
     37 function calls in 0.000 seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.000 0.000 0.000 0.000 :0(array) 
     1 0.000 0.000 0.000 0.000 :0(exec) 
     11 0.000 0.000 0.000 0.000 :0(getattr) 
     1 0.000 0.000 0.000 0.000 :0(hasattr) 
     5 0.000 0.000 0.000 0.000 :0(isinstance) 
     1 0.000 0.000 0.000 0.000 :0(setprofile) 
     5 0.000 0.000 0.000 0.000 :0(update) 
     1 0.000 0.000 0.000 0.000 :0(zeros) 
     1 0.000 0.000 0.000 0.000 <string>:1(<module>) 
     1 0.000 0.000 0.000 0.000 core.py:2704(__new__) 
     1 0.000 0.000 0.000 0.000 core.py:2838(_update_from) 
     1 0.000 0.000 0.000 0.000 core.py:2864(__array_finalize__) 
     5 0.000 0.000 0.000 0.000 core.py:3264(__setattr__) 
     1 0.000 0.000 0.000 0.000 core.py:6119(array) 
     0 0.000    0.000   profile:0(profiler) 
     1 0.000 0.000 0.000 0.000 profile:0(q.np.ma.array(q.data, mask=False, copy=False)) 

所以看起來陣列的連接步驟是瓶頸。