代码之家  ›  专栏  ›  技术社区  ›  Fnord

具有屏蔽索引的numpy数组上的向量化和运算

  •  3
  • Fnord  · 技术社区  · 6 年前

    我想做一个 vectorized sum 使用 numpy 的数组 masked 指数

    例如,如果没有遮罩:

    import numpy as np
    
    # data to be used in a vectorized sum operation
    data = np.array([[1,0,0,0,0,0],
                     [0,1,0,0,0,0],
                     [0,0,1,0,0,0]])
    
    # data indices i wish to sum together
    idx = np.array([[0,1,2],   # sum data rows 0,1 and 2
                    [2,1,1]])  # sum data rows 2,1 and 1
    
    # without a mask this is straighforward
    print np.sum(data[idx],axis=1)
    #[[1 1 1 0 0 0]
    # [0 2 1 0 0 0]]
    

    现在使用掩码时,如果不在掩码索引数组上循环,我想不出如何执行此操作:

    # introduce a mask
    mask = np.array([[True,  True, True],  # sum data rows 0,1 and 2
                     [False, True, True]]) # sum data rows 1 and 1 (masking out idx[1,0])
    
    summed = np.zeros((idx.shape[0],data.shape[1]),dtype='int')
    for i in xrange(idx.shape[0]):
        summed[i] =  np.sum(data[idx[i][mask[i]]],axis=0)
    print summed
    #[[1 1 1 0 0 0]
     #[0 2 0 0 0 0]]
    

    问题

    有没有合适的方法来实现这种无回路的操作?

    1 回复  |  直到 6 年前
        1
  •  3
  •   Divakar    6 年前

    你可以用 np.einsum -

    v = data[idx]
    summed = np.einsum('ijk,ij->ik', v, mask)
    

    在给定样本上运行-

    In [43]: v = data[idx]
    
    In [44]: np.einsum('ijk,ij->ik', v, mask)
    Out[44]: 
    array([[1, 1, 1, 0, 0, 0],
           [0, 2, 0, 0, 0, 0]])
    

    或者,使用 np.matmul -

    In [67]: np.matmul(v.swapaxes(1,2), mask[...,None])[...,0]
    Out[67]: 
    array([[1, 1, 1, 0, 0, 0],
           [0, 2, 0, 0, 0, 0]])
    
    # Put another way
    In [80]: np.matmul(mask[:,None,:], v)[:,0]
    Out[80]: 
    array([[1, 1, 1, 0, 0, 0],
           [0, 2, 0, 0, 0, 0]])
    

    保持循环并提高性能

    如果循环不够,并且每次迭代都有足够的求和减少,那么可以用矩阵乘法代替迭代操作。因此-

    for i in xrange(idx.shape[0]):
        summed[i] = mask[i].dot(data[idx[i]])