2014-01-28 47 views
4

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

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切片。在正常情况下,这很容易。为了得到我会简单地使用a[1:4,1,4]这将产生紧邻2,2单元的预期

[[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片段来环绕数组的边缘?

提前感谢任何能够帮助的人。

+0

你为什么不只是压平,然后重塑数组,然后使用'array.take我已经“花哨索引”和利用meshgrid功能解决了这个(indices,mode ='wrap')'? – agconti

+1

看起来像这个问题:http://stackoverflow.com/questions/4148292/how-do-i-select-a-window-from-a-numpy-array-with-periodic-boundary-conditions虽然它看起来像那样一个给出一个副本,而不是一个视图... – IanH

+0

@IanH - 是的,这似乎做我想要的。谢谢。在发帖之前我没有看到那个人。 –

回答

7

在使用各种方法玩了一段时间后,我刚来到一个相当简单的解决方案,使用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见过,但我还没有看到任何人解释它如何会与前一个二维阵列中使用,所以我的希望张贴这也可以帮助别人将来也会有同样的问题。

1

您还可以使用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

正如我在评论中提到的,在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.]] 
10

这将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]]) 

垫程序有一个“包裹”的方法......

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

+0

+1:比如说,你想打包的卷积,这是一个很好的解决方案。谢谢,我不知道'pad'(并且在我需要时手动完成此操作..不再)。 – tom10

1

我有一个类似的挑战与环绕索引工作,只在我的情况下,我需要在原始矩阵中设置值。

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]]