2017-10-06 80 views
2

我想實現一個函數,它接受numpy二維數組中的每一行,並返回某個特定計算的標量結果。我當前的代碼如下所示:numpy apply_along_axis vectorisation

img = np.array([ 
    [0, 5, 70, 0, 0, 0 ], 
    [10, 50, 4, 4, 2, 0 ], 
    [50, 10, 1, 42, 40, 1 ], 
    [10, 0, 0, 6, 85, 64], 
    [0, 0, 0, 1, 2, 90]] 
) 

def get_y(stride): 
    stride_vals = stride[stride > 0] 
    pix_thresh = stride_vals.max() - 1.5*stride_vals.std() 
    return np.argwhere(stride>pix_thresh).mean() 

np.apply_along_axis(get_y, 0, img) 
>> array([ 2. , 1. , 0. , 2. , 2.5, 3.5]) 

它能正常工作,但是性能還是不理想在現實的數據集有〜2K行〜20-50列每一幀,未來60倍第二。

有沒有辦法加快進程,也許沒有使用np.apply_along_axis函數?

+0

我認爲apply_along_axis比簡單的行迭代慢。 – hpaulj

+0

@hpaulj我測試了它,它的速度確實稍慢一點。這有什麼特別的理由嗎?如果沿軸應用通常比行迭代慢,那麼具有這樣的功能有什麼意義呢? – ymoiseev

+1

方便。這是Python代碼,你可以閱讀。它不會編譯循環或函數的評估。它只是概括了循環,使得更易於表達多維度評估(即4d陣列中的其他3個)。它使用'np.ndindex'來生成循環索引。 – hpaulj

回答

2

這裏有一個量化的方法設置zerosNaN,並且讓我們用np.nanmaxnp.nanstd計算那些maxstd值避免zeros,像這樣 -

imgn = np.where(img==0, np.nan, img) 
mx = np.nanmax(imgn,0) # np.max(img,0) if all are positive numbers 
st = np.nanstd(imgn,0) 
mask = img > mx - 1.5*st 
out = np.arange(mask.shape[0]).dot(mask)/mask.sum(0) 

運行測試 -

In [94]: img = np.random.randint(-100,100,(2000,50)) 

In [95]: %timeit np.apply_along_axis(get_y, 0, img) 
100 loops, best of 3: 4.36 ms per loop 

In [96]: %%timeit 
    ...: imgn = np.where(img==0, np.nan, img) 
    ...: mx = np.nanmax(imgn,0) 
    ...: st = np.nanstd(imgn,0) 
    ...: mask = img > mx - 1.5*st 
    ...: out = np.arange(mask.shape[0]).dot(mask)/mask.sum(0) 
1000 loops, best of 3: 1.33 ms per loop 

因此,我們看到3x+加速。

+1

謝謝,這個工程很好。對於較大的圖像,它可以提供100倍以上的加速! – ymoiseev