2015-12-17 14 views
8

Numpyアレイでブロックワイズ操作を行うための便利なユーティリティはありますか?Numpyのブロックワイズ操作

私は、行列をブロックに分割し、各ブロックがその合計、平均または他の関数に置き換えられる行列を返す、スピン再正規化のような操作を考えています。

答えて

6

superbatfish's blockwise_viewを探している可能性があります。これはnp.lib.stride_tricks.as_stridedを使用して配列のビューを作成し、配列の「ブロック」を独自の軸に配置します。

は、たとえば、次のような2次元アレイがあると、

In [97]: arr = np.arange(24).reshape(6, 4) 

In [98]: arr.shape 
Out[98]: (6, 4) 

In [99]: arr 
Out[99]: 
array([[ 0, 1, 2, 3], 
     [ 4, 5, 6, 7], 
     [ 8, 9, 10, 11], 
     [12, 13, 14, 15], 
     [16, 17, 18, 19], 
     [20, 21, 22, 23]]) 

とシェイプの4つのブロックに「それをチョップ」したい(3、2)。今、あなたはそれを再構築できた一つのブロックからのすべての値が最後の軸である

In [34]: blocked = blockwise_view(arr, (3, 2)); blocked 
Out[34]: 
array([[[[ 0, 1], 
     [ 4, 5], 
     [ 8, 9]], 

     [[ 2, 3], 
     [ 6, 7], 
     [10, 11]]], 


     [[[12, 13], 
     [16, 17], 
     [20, 21]], 

     [[14, 15], 
     [18, 19], 
     [22, 23]]]]) 

In [37]: blocked.shape 
Out[37]: (2, 2, 3, 2) 

あなたは(4、3 2)形状の4D配列に変換する blockwise_viewを使用することができます
In [41]: reshaped = blocked.reshape(-1, 3*2); reshaped 
Out[41]: 
array([[ 0, 1, 4, 5, 8, 9], 
     [ 2, 3, 6, 7, 10, 11], 
     [12, 13, 16, 17, 20, 21], 
     [14, 15, 18, 19, 22, 23]]) 

今、あなたは、その軸に沿って合計し、またはその平均を取るか、各ブロックの要素に他のいくつかの機能を適用することができます。

In [103]: reshaped.sum(axis=-1) 
Out[103]: array([ 27, 39, 99, 111]) 

In [104]: reshaped.mean(axis=-1) 
Out[104]: array([ 4.5, 6.5, 16.5, 18.5]) 

my first answerとは異なり、whic hは2D配列にのみ適用でき、 blockwise_viewは任意のN次元配列に適用できます。 2 N次元配列を返します。最初のN軸はブロックをインデックスします。

+0

Scikitにview_as_windows' 'もありますScikit-learnで-imageと 'extract_patches'を実行します。 –

2

ブロック単位操作をスライドさせるため、あなたが列にImplement Matlab's im2col_sliding 'sliding' in pythonそのグループから各ブロックの実装を借りることができ、それによってブロックワイズ操作がaxis = 0に沿ってそのように動作するベクトル化ソリューションのすべてNumPy ufuncsを受け入れるように簡単になります。等のブロック状sumaveragestdを計算する

def im2col_sliding(A,BLKSZ): 

    # Parameters 
    M,N = A.shape 
    col_extent = N - BLKSZ[1] + 1 
    row_extent = M - BLKSZ[0] + 1 

    # Get Starting block indices 
    start_idx = np.arange(BLKSZ[0])[:,None]*N + np.arange(BLKSZ[1]) 

    # Get offsetted indices across the height and width of input array 
    offset_idx = np.arange(row_extent)[:,None]*N + np.arange(col_extent) 

    # Get all actual indices & index into input array for final output 
    return np.take (A,start_idx.ravel()[:,None] + offset_idx.ravel()) 

サンプル実行 - - ここで関数を作成するようにスライディングブロックを定義するための正式な方法だ

In [6]: arr     # Sample array 
Out[6]: 
array([[6, 5, 0, 6, 0], 
     [7, 4, 2, 3, 6], 
     [6, 3, 3, 8, 1], 
     [5, 5, 1, 1, 8]]) 

In [7]: im2col_sliding(arr,[2,3]) # Blockwise array with blocksize : (2,3) 
Out[7]: 
array([[6, 5, 0, 7, 4, 2, 6, 3, 3], 
     [5, 0, 6, 4, 2, 3, 3, 3, 8], 
     [0, 6, 0, 2, 3, 6, 3, 8, 1], 
     [7, 4, 2, 6, 3, 3, 5, 5, 1], 
     [4, 2, 3, 3, 3, 8, 5, 1, 1], 
     [2, 3, 6, 3, 8, 1, 1, 1, 8]]) 

In [8]: np.sum(im2col_sliding(arr,[2,3]),axis=0) # Perform blockwise summation 
Out[8]: array([24, 20, 17, 25, 23, 23, 23, 21, 22]) 

In [9]: np.mean(im2col_sliding(arr,[2,3]),axis=0) # Perform blockwise averaging 
Out[9]: 
array([ 4.  , 3.33333333, 2.83333333, 4.16666667, 3.83333333, 
     3.83333333, 3.83333333, 3.5  , 3.66666667]) 

In [10]: np.std(im2col_sliding(arr,[2,3]),axis=0) # Blockwise std. deviation 
Out[10]: 
array([ 2.38047614, 1.97202659, 2.47767812, 1.77169097, 1.95078332, 
     2.40947205, 1.67497927, 2.43241992, 3.14466038])