簡體   English   中英

在numpy中圍繞2D數組的邊緣包裹切片

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

假設我在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數組?

提前感謝任何可以提供幫助的人。

這將適用於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周圍的填充。

在使用各種方法一段時間后,我只是找到了一個使用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數組一起使用的,所以我發布這個希望它可以幫助有同樣問題的人在將來。

您還可以使用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]])

我使用環繞式索引進行了類似的挑戰,僅在我的情況下我需要在原始矩陣中設置值。 我通過'花式索引'並使用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]]

正如我在評論中提到的, 如何從具有周期性邊界條件的numpy數組中選擇窗口 ,這是一個很好的答案

這是另一種簡單的方法

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM