Niezgrabny wycinek indeksu bez utraty informacji o wymiarach

100

Używam numpy i chcę indeksować wiersz bez utraty informacji o wymiarze.

import numpy as np
X = np.zeros((100,10))
X.shape        # >> (100, 10)
xslice = X[10,:]
xslice.shape   # >> (10,)  

W tym przykładzie xslice jest teraz 1 wymiarem, ale chcę, aby był (1,10). W R użyłbym X [10,:, drop = F]. Czy jest coś podobnego w numpy. Nie mogłem znaleźć tego w dokumentacji i nie widziałem zadanego podobnego pytania.

Dzięki!

mindmatters
źródło

Odpowiedzi:

59

Prawdopodobnie jest to najłatwiejsze x[None, 10, :]lub równoważne (ale bardziej czytelne) x[np.newaxis, 10, :].

Jeśli chodzi o to, dlaczego nie jest to wartość domyślna, osobiście uważam, że ciągłe posiadanie tablic z pojedynczymi wymiarami bardzo szybko irytuje. Domyślam się, że odrętwiali twórcy czuli to samo.

Ponadto numpy obsługuje rozgłaszanie tablic bardzo dobrze, więc zwykle nie ma powodu, aby zachować wymiar tablicy, z której pochodzi wycinek. Jeśli tak, to takie rzeczy jak:

a = np.zeros((100,100,10))
b = np.zeros(100,10)
a[0,:,:] = b

albo nie zadziała, albo będzie znacznie trudniejszy do wdrożenia.

(A przynajmniej takie jest moje przypuszczenie w rozumowaniu odrętwiałego dewelopera za upuszczaniem informacji o wymiarze podczas krojenia)

Joe Kington
źródło
6
@Lisa: x[None, 10]zrobi, co chcesz.
naught101
Tak. Umieść swoje Noneobok ciemności, które kroisz.
Mad Physicist,
1
W przykładzie brakuje dodatkowych nawiasów dla krotki w przypisaniu do b; powinno być b = np.zeros((100,10)).
Jerzy
Jaki jest powód używania łącznie 3 indeksów zamiast tylko dwóch? Mam na myśli X[10,None](używając twojego kodu jako przykładu).
greenoldman
9
zwykle nie ma powodu, aby zachować wymiar tablicy ”… Cóż, z pewnością całkowicie i całkowicie zepsuje mnożenie macierzy ( np.matmul()lub@ ). Właśnie zostałem przez to spalony.
Jean-François Corbett
93

Innym rozwiązaniem jest zrobienie

X[[10],:]

lub

I = array([10])
X[I,:]

Wymiarowość tablicy jest zachowywana, gdy indeksowanie jest wykonywane przez listę (lub tablicę) indeksów. Jest to miłe, ponieważ pozostawia wybór między zachowaniem wymiaru a ściskaniem.

gnebehay
źródło
2
To kopiuje dane tablicy
na dzień
Nie zawsze tak jest. Zobacz: x = np.array([[1,2,3,4]]) jeśli następnie pokroisz go razem x[[0],[1,2]] , uzyskasz jednowymiarowy. array([2, 3]) Moim zdaniem, wybierając wektory kolumnowe lub wierszowe, najlepiej jest uczynić ten plaster prostym, a następnie użyć np.reshape, więc w moim przykładzie byłoby tonp.reshape(x[0,[1,2]],[1,2])
Alexander
1
inni, pamiętajcie na końcu o średniku - to ważne, X[[10]]zostaną zinterpretowane jako, X[10]a kształt będzie mniejszy; podobnie, X[[10, 20]] == X[10, 20]a kształt jest jeszcze mniejszy
Ben Usman
1
Ostrzeżenie : nie mieszaj tego sposobu indeksowania tylko z indeksowaniem liczb całkowitych! Gdybyś miał akształt (10, 20, 30), to a[0, :, [0]]będzie miał kształt (1, 20), a nie (20, 1), bo w tych ostatnich są nadawane indeksy, do a[[0], :, [0]]których często nie do końca się spodziewasz! Ale a[0, :, :1]da ci (20, 1)zgodnie z oczekiwaniami. Co więcej, zobacz powyższy komentarz dla dziwnych przypadków brzegowych z pojedynczym indeksem. Ogólnie wydaje się, że ta metoda ma zbyt wiele przypadków skrajnych.
Ben Usman
30

Znalazłem kilka rozsądnych rozwiązań.

1) użycie numpy.take(X,[10],0)

2) użyj tego dziwnego indeksowania X[10:11:, :]

W idealnym przypadku powinno to być ustawienie domyślne. Nigdy nie rozumiałem, dlaczego wymiary są kiedykolwiek opuszczane. Ale to dyskusja dla numpy ...

mindmatters
źródło
2
„Wymiary” są usuwane podczas indeksowania list Pythona alist[0]i zachowywane podczas ich krojenia.
hpaulj
5
Opcja 2 (którą można zapisać jako slice(n, n+1)wyodrębnianie indeksu n) powinna być akceptowaną odpowiedzią, ponieważ jest jedyną, która rozciąga się naturalnie na przypadek n-wymiarowy.
norok2
Wydaje się, że opcja 2 może być zapisana tak, jak X[10:11, :]w Pythonie 3.7.5 (tj. Bez dodatkowego dwukropka po 11)
Joe
7

Oto alternatywa, którą lubię bardziej. Zamiast indeksowania za pomocą jednej liczby, indeksuj z zakresem. To znaczy użyj X[10:11,:]. (Uwaga: 10:11nie obejmuje 11).

import numpy as np
X = np.zeros((100,10))
X.shape        # >> (100, 10)
xslice = X[10:11,:]
xslice.shape   # >> (1,10)

Ułatwia to zrozumienie również przy większej liczbie wymiarów, bez Noneżonglowania i zastanawiania się, której osi użyć, którego indeksu. Nie ma również potrzeby wykonywania dodatkowych czynności księgowych dotyczących rozmiaru tablicy, tylko i:i+1dla itych, których używałbyś w zwykłym indeksowaniu.

b = np.ones((2, 3, 4))
b.shape # >> (2, 3, 4)
b[1:2,:,:].shape  # >> (1, 3, 4)
b[:, 2:3, :].shape .  # >> (2, 1, 4)
Andrew Schwartz
źródło
0

Jest to szczególnie denerwujące, jeśli indeksujesz według tablicy, której długość może wynosić 1 w czasie wykonywania. W takim przypadku jest np.ix_:

some_array[np.ix_(row_index,column_index)]
Jthorpe
źródło