首页 文章

在numpy中围绕2D数组的边缘包裹切片

提问于
浏览
8

假设我在Python中使用numpy并且我有一个任意大小的二维数组 . 为方便起见,假设我有一个5 x 5阵列 . 具体数字对我的问题不是特别重要;他们只是一个例子 .

a = numpy.arrange(25).reshape(5,5)

这会产生:

[[0, 1, 2, 3, 4 ],
 [5, 6, 7, 8, 9 ],
 [10,11,12,13,14],
 [15,16,17,18,19],
 [20,21,22,23,24]]

现在,假设我想拍摄这个数组的2D切片 . 在正常情况下,这很容易 . 为了使细胞紧邻2,2,我只需使用 a[1:4,1,4] 即可产生预期效果

[[6, 7,   8 ],
 [11, 12, 13],
 [16, 17, 18]]

但是如果我想采取一个包裹数组边缘的切片呢?例如 a[-1:2,-1:2] 会产生:

[24, 20, 21],
[4, 0,  1 ],
[9, 5,  6 ]

这在边缘无关紧要的几种情况下是有用的,例如围绕屏幕的游戏图形 . 我意识到这可以通过很多if语句和边界检查来完成,但我想知道是否有更清洁,更惯用的方法来实现这一点 .

环顾四周,我找到了几个答案:https://stackoverflow.com/questions/17739543/wrapping-around-slices-in-python-numpy适用于一维数组,但我还没有弄清楚如何将这个逻辑应用于2D切片 .

基本上,问题是:如何在numpy中包围数组边缘的2D数组的2D切片?

提前感谢任何可以提供帮助的人 .

5 回答

  • 9

    您也可以使用roll来滚动数组然后切片:

    b = np.roll(np.roll(a, 1, axis=0), 1, axis=1)[:3,:3]
    

    array([[24, 20, 21],
           [ 4,  0,  1],
           [ 9,  5,  6]])
    
  • 0

    这将适用于numpy> = 1.7 .

    a = np.arange(25).reshape(5,5)
    
    array([[ 0,  1,  2,  3,  4],
           [ 5,  6,  7,  8,  9],
           [10, 11, 12, 13, 14],
           [15, 16, 17, 18, 19],
           [20, 21, 22, 23, 24]])
    

    pad例程有一个'wrap'方法......

    b = np.pad(a, 1, mode='wrap')
    
    array([[24, 20, 21, 22, 23, 24, 20],
           [ 4,  0,  1,  2,  3,  4,  0],
           [ 9,  5,  6,  7,  8,  9,  5],
           [14, 10, 11, 12, 13, 14, 10],
           [19, 15, 16, 17, 18, 19, 15],
           [24, 20, 21, 22, 23, 24, 20],
           [ 4,  0,  1,  2,  3,  4,  0]])
    

    根据情况,您可能必须为任何切片的每个术语添加1,以便考虑 b 周围的填充 .

  • 1

    在使用各种方法一段时间后,我刚刚找到了一个使用 ndarray.take 的相当简单的解决方案 . 使用我在问题中提供的示例:

    a.take(range(-1,2),mode='wrap', axis=0).take(range(-1,2),mode='wrap',axis=1)
    

    提供所需的输出

    [[24 20 21]
     [4  0   1]
     [9  5  6]]
    

    事实证明它比我想象的要简单得多 . 如果您反转两个轴,此解决方案也适用 .

    这类似于我以前使用 take 看到的答案,但我之前没有使用过2D阵列,所以我发布这个希望它可以帮助将来有同样问题的人 .

  • 12

    我使用环绕式索引进行了类似的挑战,仅在我的情况下我需要在原始矩阵中设置值 . 我通过'花式索引'并使用meshgrid函数解决了这个问题:

    A = arange(25).reshape((5,5)) # destinatoin matrix
    print 'A:\n',A
    
    k =-1* np.arange(9).reshape(3,3)# test kernel, all negative
    print 'Kernel:\n', k
    ix,iy = np.meshgrid(arange(3),arange(3)) # create x and y basis indices
    
    pos = (0,-1) # insertion position
    
    # create insertion indices
    x = (ix+pos[0]) % A.shape[0]
    y = (iy+pos[1]) % A.shape[1]
    A[x,y] = k # set values
    print 'Result:\n',A
    

    输出:

    A:
    [[ 0  1  2  3  4]
     [ 5  6  7  8  9]
     [10 11 12 13 14]
     [15 16 17 18 19]
     [20 21 22 23 24]]
    Kernel:
    [[ 0 -1 -2]
     [-3 -4 -5]
     [-6 -7 -8]]
    Result:
    [[-3 -6  2  3  0]
     [-4 -7  7  8 -1]
     [-5 -8 12 13 -2]
     [15 16 17 18 19]
     [20 21 22 23 24]]
    
  • 1

    正如我在评论中提到的,How do I select a window from a numpy array with periodic boundary conditions?有一个很好的答案

    这是另一种简单的方法

    # First some setup
    import numpy as np
    A = np.arange(25).reshape((5, 5))
    m, n = A.shape
    

    然后

    A[np.arange(i-1, i+2)%m].reshape((3, -1))[:,np.arange(j-1, j+2)%n]
    

    获得可以分配的东西有点困难 . 这是一个有点慢的版本 . 为了获得类似的值,我将不得不这样做

    A.flat[np.array([np.arange(j-1,j+2)%n+a*n for a in xrange(i-1, i+2)]).ravel()].reshape((3,3))
    

    为了赋予它,我将不得不避免调用重塑并直接使用花式索引返回的展平版本 . 这是一个例子:

    n = 7
    A = np.zeros((n, n))
    for i in xrange(n-2, 0, -1):
        A.flat[np.array([np.arange(i-1,i+2)%n+a*n for a in xrange(i-1, i+2)]).ravel()] = i+1
    print A
    

    返回

    [[ 2.  2.  2.  0.  0.  0.  0.]
     [ 2.  2.  2.  3.  0.  0.  0.]
     [ 2.  2.  2.  3.  4.  0.  0.]
     [ 0.  3.  3.  3.  4.  5.  0.]
     [ 0.  0.  4.  4.  4.  5.  6.]
     [ 0.  0.  0.  5.  5.  5.  6.]
     [ 0.  0.  0.  0.  6.  6.  6.]]
    

相关问题