简体   繁体   English

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

[英]Wrap slice around edges of a 2D array in numpy

Suppose I am working with numpy in Python and I have a two-dimensional array of arbitrary size. 假设我在Python中使用numpy并且我有一个任意大小的二维数组。 For convenience, let's say I have a 5 x 5 array. 为方便起见,假设我有一个5 x 5阵列。 The specific numbers are not particularly important to my question; 具体数字对我的问题不是特别重要; they're just an example. 他们只是一个例子。

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

This yields: 这会产生:

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

Now, let's say I wanted to take a 2D slice of this array. 现在,假设我想拍摄这个数组的2D切片。 In normal conditions, this would be easy. 在正常情况下,这很容易。 To get the cells immediately adjacent to 2,2 I would simply use a[1:4,1,4] which would yield the expected 为了使细胞紧邻2,2,我只需使用a[1:4,1,4]产生预期的细胞

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

But what if I want to take a slice that wraps around the edges of the array? 但是,如果我想采取一个包裹阵列边缘的切片呢? For example a[-1:2,-1:2] would yield: 例如a[-1:2,-1:2]会产生:

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

This would be useful in several situations where the edges don't matter, for example game graphics that wrap around a screen. 这在边缘无关紧要的几种情况下是有用的,例如围绕屏幕的游戏图形。 I realize this can be done with a lot of if statements and bounds-checking, but I was wondering if there was a cleaner, more idiomatic way to accomplish this. 我意识到这可以通过很多if语句和边界检查来完成,但我想知道是否有更简洁,更惯用的方法来实现这一点。

Looking around, I have found several answers such as this: https://stackoverflow.com/questions/17739543/wrapping-around-slices-in-python-numpy that work for 1-dimensional arrays, but I have yet to figure out how to apply this logic to a 2D slice. 环顾四周,我找到了几个答案: https//stackoverflow.com/questions/17739543/wrapping-around-slices-in-python-numpy适用于一维数组,但我还没弄清楚如何将此逻辑应用于2D切片。

So essentially, the question is: how do I take a 2D slice of a 2D array in numpy that wraps around the edges of the array? 基本上,问题是:如何在numpy中包围数组边缘的2D数组?

Thank you in advance to anyone who can help. 提前感谢任何可以提供帮助的人。

This will work with numpy >= 1.7. 这将适用于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]])

The pad routine has a 'wrap' method... 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]])

Depending on the situation you may have to add 1 to each term of any slice in order to account for the padding around b . 根据情况,您可能必须为任何切片的每个术语添加1,以便考虑b周围的填充。

After playing around with various methods for a while, I just came to a fairly simple solution that works using ndarray.take . 在使用各种方法一段时间后,我只是找到了一个使用ndarray.take工作的相当简单的解决方案。 Using the example I provided in the question: 使用我在问题中提供的示例:

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

Provides the desired output of 提供所需的输出

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

It turns out to be a lot simpler than I thought it would be. 事实证明它比我想象的要简单得多。 This solution also works if you reverse the two axes. 如果您反转两个轴,此解决方案也适用。

This is similar to the previous answers I've seen using take , but I haven't seen anyone explain how it'd be used with a 2D array before, so I'm posting this in the hopes it helps someone with the same question in the future. 这类似于我之前看到的使用take答案,但我还没有看到有人解释它之前是如何与2D数组一起使用的,所以我发布这个希望它可以帮助有同样问题的人在将来。

You can also use roll , to roll the array and then take your slice: 您还可以使用roll ,滚动数组,然后切片:

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

gives

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

I had a similar challenge working with wrap-around indexing, only in my case I needed to set values in the original matrix. 我使用环绕式索引进行了类似的挑战,仅在我的情况下我需要在原始矩阵中设置值。 I've solved this by 'fancy indexing' and making use of meshgrid function: 我通过'花式索引'并使用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

The output: 输出:

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

As I mentioned in the comments, there is a good answer at How do I select a window from a numpy array with periodic boundary conditions? 正如我在评论中提到的, 如何从具有周期性边界条件的numpy数组中选择窗口 ,这是一个很好的答案

Here is another simple way to do this 这是另一种简单的方法

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

and then 然后

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

It is somewhat harder to obtain something that you can assign to. 获得可以分配的东西有点难。 Here is a somewhat slower version. 这是一个有点慢的版本。 In order to get a similar slice of values I would have to do 为了获得类似的值,我将不得不这样做

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

In order to assign to this I would have to avoid the call to reshape and work directly with the flattened version returned by the fancy indexing. 为了赋予它,我将不得不避免调用重新整形并直接使用由花式索引返回的扁平化版本。 Here is an example: 这是一个例子:

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

which returns 返回

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM