在多维numpy数组中迭代向量

时间:2013-02-22 01:38:45

标签: python numpy

我有一个3xNxM numpy数组a,我想迭代最后两个轴: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风格的方法是将(3,N * M)和M重塑为(3,3 * N * M)并采用点积,但这会占用大量内存。 / p>

2 个答案:

答案 0 :(得分: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

编辑 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]]])

答案 1 :(得分: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]]])

说明:

对于多维数组,np.dot(M,a) performs a sum product over the last axis of M and the second-to-last axis of a.

a具有形状(3,4,5),但我们希望在形状为3的轴上求和。由于倒数第二个轴将被求和,我们需要{{1 - 具有形状(4,3,5) - 将3移动到倒数第二个轴。

a.swapaxis(0,1)有形状(3,3),M有形状(4,3,5)。删除a.swapaxis(0,1)的最后一个轴和M的倒数第二个轴会留下(3,)和(4,5),因此a.swapaxis(0,1)返回的结果是形状数组(3,4,5) - 正是我们想要的。