如何在左侧和右侧填充每行可变长度的2d数组,以形成更大的2d数组

时间:2018-04-26 11:55:04

标签: python numpy

我有一个像

这样的二维数组
small = np.arange(9).reshape((3, 3))

array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

我想应用填充,每行填充左侧的变量0。并确保结果2d数组的形状为3 x 8.(右侧填充0)

offset = np.array([1, 3, 2])

结果看起来像

array([[ 0.,  0.,  1.,  2.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  3.,  4.,  5.,  0.,  0.],
       [ 0.,  0.,  6.,  7.,  8.,  0.,  0.,  0.]])

实现这一目标的最佳方式是什么?

感谢@Divakar解决方案。我在以下方法上运行了一些基准测试。

def f1(small, offset, ncols):
    nrows, num_small_cols = small.shape
    big = np.zeros((nrows, ncols))
    inner = np.empty_like(small, dtype=np.int64)
    for i in range(num_small_cols):
        inner[:, i] = offset + i
    big[np.arange(nrows)[:, None], inner] = small
    return big

def f2(small, offset, ncols):
    n = small.shape[1]
    r = np.arange(ncols)
    offset2 = offset[:,None]
    # This took a lot of time
    mask = (offset2 <= r) & (offset2 + n > r)
    out = np.zeros_like(mask, dtype=np.float64)
    out[mask] = small.ravel()
    return out

def f3(small, offset, ncols):
    n = small.shape[1]
    m = ncols - n
    small_pad = np.zeros((len(small), n + 2*m))
    small_pad[:,m:m+n] = small    
    w = view_as_windows(small_pad, (1,ncols))[:,:,0]
    return w[np.arange(len(offset)), ncols-offset-n]

n = 10000
offset = np.repeat(np.array([1, 3, 2]), n)
small = np.random.rand(n * 3, 5)

%timeit f1(small, offset, 9)
# 1.32 ms

%timeit f2(small, offset, 9)
# 2.24 ms

%timeit f3(small, offset, 9)
# 1.3 ms

2 个答案:

答案 0 :(得分:4)

方法#1

我们可以使用broadcasting创建一个掩码,用于分配到这些位置,然后分配到零初始化数组 -

def pad_offsetpos(small, ncols):
    n = small.shape[1]
    r = np.arange(ncols)
    mask = (offset[:,None] <= r) & (offset[:,None]+n > r)
    out = np.zeros(mask.shape)
    out[mask] = small.ravel()
    return out

示例运行 -

In [327]: small
Out[327]: 
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

In [328]: offset
Out[328]: array([1, 3, 2])

In [329]: pad_offsetpos(small, ncols=8)
Out[329]: 
array([[0., 0., 1., 2., 0., 0., 0., 0.],
       [0., 0., 0., 3., 4., 5., 0., 0.],
       [0., 0., 6., 7., 8., 0., 0., 0.]])

方法#2

我们还可以利用基于np.lib.stride_tricks.as_stridedscikit-image's view_as_windows进行有效的补丁提取,在填充输入数组后,两边都有足够的零 -

from skimage.util.shape import view_as_windows

def pad_offsetpos_strided(small, ncols):
    n = small.shape[1]
    m = ncols - n
    small_pad = np.zeros((len(small), n + 2*m))
    small_pad[:,m:m+n] = small    
    w = view_as_windows(small_pad, (1,ncols))[:,:,0]
    return w[np.arange(len(offset)), ncols-offset-n]

答案 1 :(得分:0)

PaddedMat=numpy.zeros(shape=[3,8],dtype="float")

然后循环填充它。

PaddedMat[i,offset[i]:offset[i]+3]=small[i,:]

等...