2013-07-19 15 views
14

Mam tablicę numpy i chcę uzyskać "sąsiedztwo" i-tego punktu. Zazwyczaj używane przeze mnie tablice są dwuwymiarowe, ale poniższy przykład 1D ilustruje to, czego szukam. Jeślizawijanie wokół plasterków w Pythonie/numpy

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

Wtedy (rozmiar 5) sąsiedztwo elementu 4 jest [20,30,40,50,60], i można to łatwo uzyskać, wykonując A[i-2:i+3].

Potrzebuję jednak również okolic, aby "zawinąć" krawędzie tablicy tak, aby sąsiedztwo elementu 0 było [80,90,0,10,20], a sąsiedztwo elementu 9 to [70,80,90,0,10]. Nie mogę znaleźć eleganckiego sposobu na zrobienie tego, więc w końcu muszę użyć jakiejś skomplikowanej, denerwującej logiki za każdym razem, kiedy to się pojawi (co bardzo często jest dla mnie). W przypadku 2D sąsiedztwo punktu będzie prostokątnym układem.

Moje pytanie brzmi, czy jest jakiś sposób na wyrażenie tej "otaczającej okolicy" operacji numpy? Wolałbym coś, co zwraca fragment niż kopię, ale czytelność i szybkość to najważniejsze kwestie.

+2

Zauważ, że zasadniczo nie można uzyskać widoku takiej podprzestrzeni w numpy; subarray nie może być wyrażony za pomocą pojedynczego kroku dla każdej osi –

Odpowiedz

21

numpy.take w trybie 'wrap' użyjecie twoich indeksów modulo długości tablicy.

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

Patrz dokumentacja dla szczegółów numpy.take

+3

Pokonaj mnie przez 10 sekund. Hmmph! Zauważ, że możesz również uzyskać dostęp do 'take' jako metody tablicowej, tj.' A.take (indices, mode = 'wrap') '. – DSM

+0

Dzięki @DSM, edytowane, ponieważ w tym przypadku lepiej jest użyć metody własnej instancji. – Henrik

+0

Ah. Zapomniałem wspomnieć, że moja tablica jest dwuwymiarowa - po prostu użyłem tablicy 1D, aby uczynić problem jaśniejszym. – Nathaniel

5

można użyć argumentu axis=0 z numpy.take dla n-d tablicy.

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

To samo axis=0 będzie pracować dla n * m Wymiary ...

3

Wiem, że to pytanie jest stary, ale należy wspomnieć scipy.ndimage.filter.generic_filter.

Posiada opcję mode='wrap', dodatkowo obsługuje aplikację funkcji sąsiedniej.

import scipy.ndimage as nd 

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

Powiedzmy, że masz funkcję sąsiada:

def nbf(arr): 
    return sum(arr) 

Aby zastosować funkcję sąsiada do każdego 5, z owiniętymi wartości na krawędziach:

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

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

Można użyć NP. rutynowa podpowiedź:

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] 

Powiedzmy, że masz funkcję sąsiada:

def nbf(arr): 
    return sum(arr) 

Aby zastosować funkcję sąsiad co 5 trzeba uważać o swoich początkowych i końcowych indeksów (w zakresie (...) komend) i względną kawałek ty wziąć z 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 mogą przesuwać tablicę tak, że cały kawałek jest na początku tablicy. Następnie weź swój plasterek na początku i numpy.roll ponownie, aby przywrócić tablicę do pierwotnej pozycji.

# 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 nie działa dobrze dla mnie na dużych tablicach jednak.

2

Uwaga: W przypadkach, gdzie twoi sąsiedzi nie wymagają opakowania, numpy.take jest wolniejsze niż po prostu biorąc kawałek A[i-2:i+3]. Możesz owinąć funkcję sąsiadów z niektórych instrukcji warunkowych:

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 

Jeśli znajdziesz się biorąc sąsiadów podczas iteracja tablicy, jak w środku średniej ruchomej, przekonasz się, że to wymaga mniej czasu, zwłaszcza dla dłuższych tablic:

enter image description here

Oto średnia ruchoma funkcja użyłem:

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 

I "jestem pewien, że te funkcje można dalej poprawić. Jestem otwarty na sugestie.

Powiązane problemy