为矩阵中的每个元素填充 N 维矩阵 - Python

Padding an N-dimension Matrix with different paddings for each element in the matrix - Python

提问人:Paddy 提问时间:12/30/2021 更新时间:12/31/2021 访问量:263

问:

我正在尝试用不同的填充填充 N 维矩阵的二维并覆盖这些值。请看以下示例:

def determineShifts(layer):
    u = range(0, 2*layer + 1)
    b = range(0, 2*layer + 1)
    shifts = []
    mat = np.zeros((2 * layer + 1, 2 * layer + 1), dtype=object)
    for x, i in enumerate(u):
        for y, j in enumerate(b):
            up = (j, 2*layer - j)
            left = (i, 2*layer - i)
            mat[x, y] = (left, up)
    return mat

layer = 1

b = np.ones((3,3,3,3))
shifts = determineShifts(layer)

我想填充数组 b 的倒数第二个和最后一个维度,使得结果的形状为 (3,3,5,5) 并覆盖该矩阵的元素并对所有节点重复该过程,在本例中为 (3,3)。我宁愿覆盖这些值(目前我收到广播错误),而不是复制所需的形状并遍历第一和第二维度。下面包括一个示例:

c = np.ones((3,3,5,5))
for i in range(np.shape(c)[0]):
    for j in range(np.shape(c)[1]):
        c[i,j] = np.pad(b[i,j], shifts[i,j])

有没有办法将函数应用于矩阵,以将所有移位应用于每个元素 (3,3, 3, 3) -> (3, 3, 5, 5),以便代码在计算上是有效的?

Python Matrix 多维数组 切片

评论


答:

0赞 Pierre D 12/31/2021 #1

np.pad()根据您的示例,每个轴接受不同的填充值,但不能接受每个轴的不同填充值。

一种通用方法是对元素的重新定位进行一些算术运算,然后使用花哨的索引。在您的例子中,您似乎正在尝试错开最后两个维度的 2D 块,使它们以 1 移动:轴 0 垂直移动,轴 1 水平移动。

您可以使用以下算术执行相同的操作:

def stagger_ix(s):
    r = np.arange(np.prod(s))
    block = r // np.prod(s[-2:])
    shift_i, shift_j = block // s[1], block % s[1]
    i, j = r // s[-1] % s[-2], r % s[-1]
    
    newshape = np.array(s)
    newshape[-2:] += newshape[:2] - 1
    
    ix = (
        block * np.prod(newshape[-2:])
        + (i + shift_i) * newshape[-1]
        + (j + shift_j)
    )
    return newshape, ix

def stagger(b):
    newshape, ix = stagger_ix(b.shape)

    # now insert b in a zero(newshape), as per shift logic
    c = np.zeros(np.prod(newshape), dtype=b.dtype)
    c[ix] = b.ravel()
    c = c.reshape(newshape)
    return c

您的阵列可以通过以下方式获取:c

c = stagger(np.ones((3,3,3,3)))

其他例子 -

# for example matrices
def rp1(s):
    return (np.arange(np.prod(s)) + 1).reshape(s)

>>> stagger(rp1((2,2,2,2)))
array([[[[ 1,  2,  0],
         [ 3,  4,  0],
         [ 0,  0,  0]],

        [[ 0,  5,  6],
         [ 0,  7,  8],
         [ 0,  0,  0]]],


       [[[ 0,  0,  0],
         [ 9, 10,  0],
         [11, 12,  0]],

        [[ 0,  0,  0],
         [ 0, 13, 14],
         [ 0, 15, 16]]]])
>>> stagger(rp1((2,3,2,5)))
array([[[[ 1,  2,  3,  4,  5,  0,  0],
         [ 6,  7,  8,  9, 10,  0,  0],
         [ 0,  0,  0,  0,  0,  0,  0]],

        [[ 0, 11, 12, 13, 14, 15,  0],
         [ 0, 16, 17, 18, 19, 20,  0],
         [ 0,  0,  0,  0,  0,  0,  0]],

        [[ 0,  0, 21, 22, 23, 24, 25],
         [ 0,  0, 26, 27, 28, 29, 30],
         [ 0,  0,  0,  0,  0,  0,  0]]],


       [[[ 0,  0,  0,  0,  0,  0,  0],
         [31, 32, 33, 34, 35,  0,  0],
         [36, 37, 38, 39, 40,  0,  0]],

        [[ 0,  0,  0,  0,  0,  0,  0],
         [ 0, 41, 42, 43, 44, 45,  0],
         [ 0, 46, 47, 48, 49, 50,  0]],

        [[ 0,  0,  0,  0,  0,  0,  0],
         [ 0,  0, 51, 52, 53, 54, 55],
         [ 0,  0, 56, 57, 58, 59, 60]]]])

评论

0赞 Pierre D 1/5/2022
当前答案是否有任何问题/反例?
0赞 Paddy 1/5/2022
如果每个轴上总是有一个偏移,则此解决方案有效。在一些矩阵中,我想根据条件以不同的方式映射填充。提供的解决方案在 (3,3,3,3) -> (3,3,5,5) 中效果很好。但是,在 (x, y) 的任一轴上,映射可能是 (5,5,3,3) -> (5,5,5,5) (不是 (5,5,7,7)),具体取决于我们是在 x 还是 y 处。在这些点上,完成的矩阵应该是每个 3 x 3(L、R、T、B:左、右、顶和下各一个零的填充)顶行:(2R、2B) (2R、2B) (1L1R、2B) (2L、2B) (2L、2B) 2:“” 3:(2R、1T1B) ...(2L,1T1B)4:(2L,2T)...(2L, 2T) 5: “”