2017-09-02 7 views
1

3Dまたは4Dアレイ全体で操作をしようとしていますが、サイズの小さいサブグループ(大きな配列に含まれる2D配列)3Dまたは4D Numpy配列は、2Dマスクと行列操作を使用してインデックス化されています

例:

fooは

私の質問があり、入力の操作のいくつかの並べ替えである

input = np.arange(75).reshape((3, 5, 5)) # or any other 3D or 4D matrix. 
mask_hor = np.arange(-1, 2) 
mask_ver = mask_hor[:, None] 

output = np.zeros((3, 3, 3)) 

for i in range(1, 5): 
    for j in range(1, 5): 
    output[:, i-1, j-1] = foo(input[:, i+mask_ver, j+mask_hor]) 

: 私は私が得ることができるように、入力に渡すことができる方法/マスクがありますネストされたforループを取り除く?私は主にスピードアップを探しています。

ありがとうございました!

+1

最後の2つの軸に沿ってスライドウィンドウを表示したいように見えます。だから、skimageを使うことができます: 'skimage.util.shape import view_as_windows、 out = view_as_windows(入力、(1,3,3))'。次に、 'out'の最後の2つの軸に沿って' foo'を使います。 – Divakar

+0

返信いただきありがとうございます!はい、私は完全にその用語が存在することを忘れていた(スライディングウィンドウ)。これは私の問題の半分を解決します。ありがとうございました! –

答えて

1

これは、エレガントなものよりも迅速で汚れた最適化のほうがはるかに優れています。議論のために、ウィンドウの9つの要素をfoo関数として合計します。

import numpy as np 
from scipy import ndimage 

# take the sum of a 3x3 window of a matrix 
def foo_lin_mat(mat): 
    return mat.sum(axis=(-2, -1)) # sum over the last two axes 

# sum up the individual matrices 
def foo_lin_nine(m1, m2, m3, m4, m5, m6, m7, m8, m9): 
    return m1 + m2 + m3 + m4 + m5 + m6 + m7 + m8 + m9 

# compute foo on an input matrix by shifting the mask around 
def nestfor(input, foo): 
    depth, n, m = input.shape 
    output = np.zeros((depth, n - 2, m - 2)) 
    mask_hor = np.arange(-1, 2) 
    mask_ver = mask_hor[:, None] 
    for i in range(1, n - 1): 
     for j in range(1, m - 1): 
      output[:, i - 1, j - 1] = foo(input[:, i + mask_ver, j + mask_hor]) 
    return output 

# compute foo on an input matrix by breaking the input matrix into 9 submatrices 
def flatargs(input, foo): 
    depth, n, m = input.shape 
    return foo(input[:, :n-2, :m-2], 
       input[:, 1:n-1, :m-2], 
       input[:, 2:, :m-2], 
       input[:, :n-2, 1:m-1], 
       input[:, 1:n-1, 1:m-1], 
       input[:, 2:, 1:m-1], 
       input[:, :n-2, 2:], 
       input[:, 1:n-1, 2:], 
       input[:, 2:, 2:],) 

# compute the sum of a window using ndimage.convolve 
def convolve(input, mask): 
    mask = np.ones((1, 3, 3)) 
    out = ndimage.convolve(input, mask) 
    # cut off the outer edges 
    return out[1:-1, 1:-1] 

私たちは3つの機能を持っています。マトリックスを取り、個々の3x3ウィンドウを集計します。私は彼らが最後に同じ行列を吐き出すことを確認しました。ベンチマークに関しては、

In [62]: %timeit nestfor(input, foo_lin_mat) 
1000 loops, best of 3: 261 µs per loop 

In [63]: %timeit flatargs(input, foo_lin_nine) 
10000 loops, best of 3: 35.8 µs per loop 

In [66]: mask = np.ones((1,3,3)) 

In [69]: %timeit convolve(input, mask) 
The slowest run took 6.12 times longer than the fastest. This could mean that an intermediate result is being cached. 
10000 loops, best of 3: 42.2 µs per loop 

e.e.e. flatargsバージョンは、元のネストされたforループバージョンよりも約7倍高速です。

foo関数が入力ウィンドウの線形関数である場合は、ここでconvolve関数のように、ndimage.convolve関数を使用してウィンドウ処理を行うこともできます。最終的なコードを読むのが少し楽になるかもしれませんが、マスクに使用する配列に注意する必要があります。

+0

コメントありがとうございます!それは働くことができます。問題は私のマスクが変わることだけです。私はコードを各パーツに適合させることができました。私は正確な値を持つ異なるセクションを持っています。しかし、それは、何の理由もなく、コードをますます長くするだけです。私は何かを試すことができます。 –

関連する問題