在numpy中插入非对齐元素的四维矩阵

时间:2014-12-01 06:48:52

标签: python arrays numpy matrix multidimensional-array

我使用 numpy 1.9 python 2.7.5 处理4维矩阵。

我正在使用3个numpy数组ABC(这是要简化的数组):

>>> A = np.ones((2,2,4,3));
>>> B = np.ones((2,2,4,3))*-1; B[0,0,1,:] = [10,11,12]; B[0,1,1,:] = [13,14,15]; B[1,0,1,:] = [16,17,18]; B[1,1,1,:] = [19,20,21];
>>> C = [[1,1],[1,1]]

根据A ,我希望B中插入C的所有元素。
例如:

  • c[0,0] = [1] => After A[0, 0, 1, :] has to be inserted B[0, 0, 1, :]
  • c[0,1] = [1] => After A[0, 1, 1, :] has to be inserted B[0, 1, 1, :]
  • c[1,0] = [1] => After A[1, 0, 1, :] has to be inserted B[1, 0, 1, :]
  • c[1,1] = [1] => After A[1, 1, 1, :] has to be inserted B[1, 1, 1, :]

我为3D数组问了同样的问题here,但是对于4D数组我得不到相同的结果(我对numpy来说很新)。

有什么想法吗?

谢谢!

2 个答案:

答案 0 :(得分:1)

您可以将阵列重塑为3d,并使用上一个问题中的解决方案:

def fn_4d(A,B,C, fn):
    shape = list(A.shape)
    A = A.reshape(-1,A.shape[-2], A.shape[-1])
    B = B.reshape(-1,B.shape[-2], B.shape[-1])
    C = np.array(C).reshape(-1)
    A2 = fn(A,B,C)
    shape[-2] += 1
    A2 = A2.reshape(shape)
    return A2

如果你的迭代解决方案是

def iter_3d(A,B,C):
    A_2 = np.zeros((A.shape[0], A.shape[1] + 1, A.shape[2]))
    for j in xrange(np.size(C, 0)):
      i = C[j]
      A_2[j, :, :] = np.concatenate((A[j, 0:i + 1, :], [B[j, i, :]], A[j, i + 1:, :]))
    return A_2

fn_4d(A, B, C, iter_3d)

这种重塑非常普遍,只要插入位于-2维度,就可以处理原始3d大小的任何内容。

concatenate的替代方法是:

  A_2[j,:,:] = np.insert(A[j,...], i+1, B[j,i,:], axis=0)

但深入研究insert,表明它实际上在做:

  A_2[j,:i+1,:] = A[j,:i+1,:]
  A_2[j,i+1,:] = B[j,i,:]
  A_2[j,i+2:,:] = A[j,i+1:,:]

这些替代方案的时间安排大致相同。

一次插入多行{3}}的3d解决方案实际上使用了布尔掩码索引:

def insert_3d2(A,B,C):
    mi = np.ravel_multi_index([np.arange(A.shape[0]), C], A.shape[:2])
    bvals = np.take(B.reshape(-1, B.shape[-1]), mi, axis=0)
    # result = np.insert(A.reshape(-1, A.shape[2]), mi + 1, bvals, axis=0)
    # which does:

    mi += np.arange(len(mi))
    A1 = A.reshape(-1, A.shape[2])
    shape = list(A1.shape)
    shape[0] += len(mi)
    A2 = np.empty(shape,dtype=A1.dtype)
    mask = np.ones(shape[0], dtype=bool)
    mask[mi] = False
    A2[mask,:] = A1
    A2[mi,:] = bvals

    A2 = A2.reshape(A.shape[0], -1, A.shape[2])
    return A2

也就是说,它构造一个布尔掩码来定义将A行放在新空数组中的位置。显然,对不连续的块进行索引几乎没有速度优势。

这里是重写掩码方法,没有任何扁平化。它始终比任何其他版本都快。我将迭代保持在C以上,因为这是查看该参数的最清晰方式。使用与mibvals类似的向量运算替换枚举(C)循环可以节省很少的时间。

def insert_3d3(A,B,C):
    # without flattening
    shape = list(A.shape)
    shape[1] += 1
    A2 = np.empty(shape, dtype=A.dtype)
    mask = np.ones(shape, dtype=bool)
    for j,i in enumerate(C):
        mask[j,i+1,:] = False
        A2[j,i+1,:] = B[j,i,:]
    A2[mask] = A.ravel()
    return A2

答案 1 :(得分:0)

Fancy indexing救援:

>>> C = np.asarray(C)
>>> D = np.ones((2,2,5,3))
>>> idx = np.arange(len(C))
>>> D[idx, C[:, 0], C[:, 1]+1] = B[idx, C[:, 0], C[:, 1]]
>>> D
array([[[[   1.,    1.,    1.],
         [   1.,    1.,    1.],
         [   1.,    1.,    1.],
         [   1.,    1.,    1.],
         [   1.,    1.,    1.]],

        [[   1.,    1.,    1.],
         [   1.,    1.,    1.],
         [   1.,    1.,    1.],
         [ 102.,  103.,  104.],
         [   1.,    1.,    1.]]],


       [[[   1.,    1.,    1.],
         [   1.,    1.,    1.],
         [  96.,   97.,   98.],
         [   1.,    1.,    1.],
         [   1.,    1.,    1.]],

        [[   1.,    1.,    1.],
         [   1.,    1.,    1.],
         [   1.,    1.,    1.],
         [   1.,    1.,    1.],
         [   1.,    1.,    1.]]]])