2017-06-13 60 views
2

我有一個3維numpy陣列,形狀爲Nx64x64。我想通過取平均值在1維和2維下采樣,產生一個Nx8x8形狀的新陣列。下采樣數組的最佳方式是什麼?

我有幾個工作實現,但我覺得必須有一個更好的方式來做到這一點。

我最初嘗試使用np.split:

def subsample(inparray, n): 
    inp = inparray.copy() 
    res = np.moveaxis(np.array(np.hsplit(inp, inp.shape[1]/n)), 1, 0) 
    res = np.moveaxis(np.array(np.split(res, inp.shape[2]/n, axis=3)), 1, 0) 
    res = np.mean(res, axis=(3,4)) 
    return res 

我也使用普通索引的嘗試:

def subsample2(inparray, n): 
    res = np.zeros((inparray.shape[0], n, n)) 
    lin = np.linspace(0, inparray.shape[1], n+1).astype(int) 
    bounds = np.stack((lin[:-1], lin[1:]), axis=-1) 

    for i, b in enumerate(bounds): 
     for j, b2 in enumerate(bounds): 
      res[:, i, j] = np.mean(inparray[:, b[0]:b[1], b2[0]:b2[1]], axis=(1,2)) 
    return res 

我已經不知道如何使用itertools.groupby,但也顯得相當複雜。

有誰知道一個乾淨的解決方案?

回答

2

整形到最後兩個軸線分裂成兩個,使得後者分裂的有長度等於塊大小的,給我們一個5D陣列,然後使用mean沿着第三和第五軸 -

BSZ = (8,8) 
m,n = a.shape[1:] 
out = a.reshape(N,m//BSZ[0],BSZ[0],n//BSZ[1],BSZ[1]).mean(axis=(2,4)) 
在較小的陣列

樣品運行具有較小塊大小(2,2) -

1)輸入:

In [271]: N = 2 

In [272]: a = np.random.randint(0,9,(N,6,6)) 

In [273]: a 
Out[273]: 
array([[[3, 1, 8, 7, 8, 2], 
     [0, 6, 2, 6, 8, 2], 
     [2, 1, 1, 0, 0, 1], 
     [8, 3, 0, 2, 8, 0], 
     [4, 7, 2, 6, 6, 7], 
     [5, 5, 1, 7, 2, 7]], 

     [[0, 0, 8, 1, 7, 6], 
     [8, 6, 5, 8, 4, 0], 
     [0, 3, 7, 7, 6, 1], 
     [7, 1, 7, 6, 3, 6], 
     [7, 6, 4, 6, 4, 5], 
     [4, 2, 0, 2, 6, 2]]]) 

2)獲取人工驗證幾個輸出值:

In [274]: a[0,:2,:2].mean() 
Out[274]: 2.5 

In [275]: a[0,:2,2:4].mean() 
Out[275]: 5.75 

In [276]: a[0,:2,4:6].mean() 
Out[276]: 5.0 

In [277]: a[0,2:4,:2].mean() 
Out[277]: 3.5 

3)使用提出的方法和手動驗證:

In [278]: BSZ = (2,2) 

In [279]: m,n = a.shape[1:] 

In [280]: a.reshape(N,m//BSZ[0],BSZ[0],n//BSZ[1],BSZ[1]).mean(axis=(2,4)) 
Out[280]: 
array([[[ 2.5 , 5.75, 5. ], 
     [ 3.5 , 0.75, 2.25], 
     [ 5.25, 4. , 5.5 ]], 

     [[ 3.5 , 5.5 , 4.25], 
     [ 2.75, 6.75, 4. ], 
     [ 4.75, 3. , 4.25]]]) 
相關問題