2013-07-19 62 views
14

我有一個numpy數組,我想獲得第i個點的「鄰居」。通常我使用的數組是二維的,但下面的一維例子說明了我在找什麼。如果在Python中包裝切片/ numpy

A = numpy.array([0,10,20,30,40,50,60,70,80,90]) 

然後元件4的(大小5)附近是[20,30,40,50,60],這可以很容易地通過執行A[i-2:i+3]來獲得。

但是,我還需要鄰域「環繞」數組的邊緣,以便元素0的鄰域爲[80,90,0,10,20],而元素9的鄰域爲[70,80,90,0,10]。我似乎無法找到一種優雅的方式來做到這一點,所以每次出現這種情況時(最常見的是這種情況),我最終不得不使用一些複雜的,煩人的邏輯。在2D情況下,點的鄰域將是矩形陣列。

所以我的問題是,有沒有一種簡潔的方式來表達這種「環繞式鄰居」操作在numpy中?我更喜歡返回一片而不是副本的東西,但可讀性和速度是最重要的考慮因素。

+2

要注意的是根本不可能得到在numpy的這樣一個子陣列的視圖;子陣列不能使用單一步幅的每個座標軸以10秒 –

回答

21

numpy.take in 'wrap' mode將使用您的索引模數組的長度。

indices = range(i-2,i+3) 
neighbourhood = A.take(indices, mode='wrap') 

的細節numpy.take

+3

打我來表示。 Hmmph!注意,你也可以使用'take'作爲數組方法,即'A.take(indices,mode ='wrap')'。 – DSM

+0

感謝@DSM,編輯,因爲它使得使用實例的自己的方法在這種情況下,更有意義。 – Henrik

+0

啊。我忘了提及我的數組是二維的 - 我只是用一維數組來解決問題。 – Nathaniel

5

查看文檔,你可以使用正d陣列的numpy.take參數axis=0

A = zip(range(0,101,10),range(0,11)) #create 2-d list 
A = numpy.array(A) #create 2-d array 
indices = range(i-2,i+3) 
neightbourhood = A.take(indices,axis=0,mode='wrap') 

同樣axis=0會爲N * m維工作...

3

我知道這個問題是舊的,但要提到scipy.ndimage.filter.generic_filter

它有一個mode='wrap'選項,再加上它處理鄰居函數的應用。

import scipy.ndimage as nd 

A = np.array([0,10,20,30,40,50,60,70,80,90]) 

假設你有一個鄰居功能:

def nbf(arr): 
    return sum(arr) 

要在邊緣應用鄰居功能每5,裹着值:

C = nd.generic_filter(A, nbf, 5, mode='wrap') 

print(C) 
[200 150 100 150 200 250 300 350 300 250] 
1

可以使用NP。像這樣的墊子程序:

A = np.array([0,10,20,30,40,50,60,70,80,90]) 
A = np.pad(A, 2, 'wrap') 
print(A) 
[80, 90, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 0, 10] 

假設你有一個鄰居功能:

def nbf(arr): 
    return sum(arr) 

要將鄰居功能每5你必須小心你的起點和終點指數(範圍在(...)命令)和相對切片你從A.

B = [nbf(A[i-2:i+3]) for i in range(2,12)] 
print(B) 
[200, 150, 100, 150, 200, 250, 300, 350, 300, 250] 
1

numpy.roll採取可以在陣列,使得整個切片是在陣列的開始偏移。然後在開始處切片,然後再次將numpy.roll恢復到原始位置。

# modify array at index i and nearest two 
# locations on each side of i, wrapping 
# around the edges 
A = np.array([0,10,20,30,40,50,60,70,80,90]) 
i = 9 
neighbors = 2 
A=np.roll(A, -i+neighbors) 
A[:5] += 1 
A=np.roll(A, i-neighbors) 

array([ 1, 11, 20, 30, 40, 50, 60, 71, 81, 91]) 

然而numpy.roll在大型數組上表現不佳。

2

注意:對於您的鄰居不需要打包的情況,numpy.take比簡單地採取切片A[i-2:i+3]要慢。您可能需要一些條件語句來包裝你的鄰居功能:

def neighbors(a,i,n): 
    N = a.shape[0] 
    if i - n < 0 and i + n > 0: 
     indices = range(i-n,i+n+1) 
     nbrs = a.take(indices, mode='wrap') 
    elif i-n < N - 1 and i+n > N - 1: 
     indices = range(i-n,i+n+1) 
     nbrs = a.take(indices, mode='wrap') 
    else: 
     nbrs = a[i-n:i+n+1] 
    return nbrs 

如果你發現自己在一箇中心的移動平均線走的鄰居,同時通過循環訪問數組一樣,你會發現,這需要更少的時間,尤其是更長的數組:

enter image description here

這裏是我使用了移動平均功能:

def moving_average(a,n=1): 
    N = a.shape[0] 
    ma = np.empty(N) 
    for i in range(N): 
     if n*2+1 > N: 
      ma[i] = a.mean() 
     else: 
      ma[i] = neighbors(a,i,n).mean() 
    return ma 

我肯定這些功能可以進一步改善。我接受建議。