2

3xNxM numpy 配列 a があり、最後の 2 つの軸 a[:,x,y] を反復処理したいと考えています。非エレガントなアプローチは次のとおりです。

import numpy as np
a = np.arange(60).reshape((3,4,5))
M = np. array([[1,0,0],
               [0,0,0],
               [0,0,-1]])

for x in arange(a.shape[1]):
    for y in arange(a.shape[2]):
        a[:,x,y] = M.dot(a[:,x,y])

これはnditerで行うことができますか?これの目的は、各エントリで行列の乗算を実行することです。たとえば、a[:,x,y] = M[:,:,x,y].dot(a[:,x,y])。別の MATLAB スタイルのアプローチは、a を (3,N*M) として、M を (3,3*N*M) として再形成し、内積を取ることですが、これは大量のメモリを消費する傾向があります。

4

2 に答える 2

5

図形をいじると、達成しようとしていることがより明確になる場合がありますが、あまり考えずにこの種の問題を処理する最も簡単な方法は、次のnp.einsumとおりです。

In [5]: np.einsum('ij, jkl', M, a)
Out[5]: 
array([[[  0,   1,   2,   3,   4],
        [  5,   6,   7,   8,   9],
        [ 10,  11,  12,  13,  14],
        [ 15,  16,  17,  18,  19]],

       [[  0,   0,   0,   0,   0],
        [  0,   0,   0,   0,   0],
        [  0,   0,   0,   0,   0],
        [  0,   0,   0,   0,   0]],

       [[-40, -41, -42, -43, -44],
        [-45, -46, -47, -48, -49],
        [-50, -51, -52, -53, -54],
        [-55, -56, -57, -58, -59]]])

さらに、多くの場合、パフォーマンス ボーナスが付属しています。

In [17]: a = np.random.randint(256, size=(3, 1000, 2000))

In [18]: %timeit np.dot(M, a.swapaxes(0,1))
10 loops, best of 3: 116 ms per loop

In [19]: %timeit np.einsum('ij, jkl', M, a)
10 loops, best of 3: 60.7 ms per loop

EDIT einsumは非常に強力なブードゥーです。次のように、OPが下のコメントで要求することもできます。

>>> a = np.arange(60).reshape((3,4,5))
>>> M = np.array([[1,0,0], [0,0,0], [0,0,-1]])
>>> M = M.reshape((3,3,1,1)).repeat(4,axis=2).repeat(5,axis=3)
>>> np.einsum('ijkl,jkl->ikl', M, b)
array([[[  0,   1,   2,   3,   4],
        [  5,   6,   7,   8,   9],
        [ 10,  11,  12,  13,  14],
        [ 15,  16,  17,  18,  19]],

       [[  0,   0,   0,   0,   0],
        [  0,   0,   0,   0,   0],
        [  0,   0,   0,   0,   0],
        [  0,   0,   0,   0,   0]],

       [[-40, -41, -42, -43, -44],
        [-45, -46, -47, -48, -49],
        [-50, -51, -52, -53, -54],
        [-55, -56, -57, -58, -59]]])
于 2013-02-22T02:41:34.543 に答える
2
for x in np.arange(a.shape[1]):
    for y in np.arange(a.shape[2]):
        a[:,x,y] = M.dot(a[:,x,y])

と同等です

a = np.dot(M,a.swapaxes(0,1))

In [73]: np.dot(M,a.swapaxes(0,1))
Out[73]: 
array([[[  0,   1,   2,   3,   4],
        [  5,   6,   7,   8,   9],
        [ 10,  11,  12,  13,  14],
        [ 15,  16,  17,  18,  19]],

       [[  0,   0,   0,   0,   0],
        [  0,   0,   0,   0,   0],
        [  0,   0,   0,   0,   0],
        [  0,   0,   0,   0,   0]],

       [[-40, -41, -42, -43, -44],
        [-45, -46, -47, -48, -49],
        [-50, -51, -52, -53, -54],
        [-55, -56, -57, -58, -59]]])

説明:

多次元配列の場合、の最後の軸と の最後から 2 番目のnp.dot(M,a) 軸で積和を実行します。Ma

a has shape (3,4,5), but we want to sum over the axis with shape 3. Since the second-to-last axis is going to be summed over, we need a.swapaxis(0,1) -- which has shape (4,3,5) -- to move the 3 into the second-to-last axis.

M has shape (3,3), a.swapaxis(0,1) has shape (4,3,5). Removing the last axis of M and the second-to-last axis of a.swapaxis(0,1) leaves you with (3,) and (4,5), so the result returned by np.dot is an array of shape (3,4,5) -- just what we want.

于 2013-02-22T01:51:21.267 に答える