Jak uzyskać dostęp do i-tej kolumny wielowymiarowej tablicy NumPy?

462

Załóżmy, że mam:

test = numpy.array([[1, 2], [3, 4], [5, 6]])

test[i]pobiera mi i-tą linię tablicy (np [1, 2].). Jak mogę uzyskać dostęp do i-tej kolumny? (np [1, 3, 5].). Czy byłby to również kosztowny zabieg?

lpl
źródło

Odpowiedzi:

686
>>> test[:,0]
array([1, 3, 5])

Podobnie,

>>> test[1,:]
array([3, 4])

umożliwia dostęp do wierszy. Jest to omówione w sekcji 1.4 (Indeksowanie) odniesienia NumPy . Jest to szybkie, przynajmniej z mojego doświadczenia. Jest to z pewnością znacznie szybsze niż dostęp do każdego elementu w pętli.

mtrw
źródło
11
Tworzy kopię, czy można uzyskać odwołanie, tak jak otrzymuję odwołanie do kolumny, każda zmiana w tym odwołaniu jest odzwierciedlona w oryginalnej tablicy.
harmands 18.10.16
@harmands Nie tworzy kopii, tworzy widok.
rinspy
69

A jeśli chcesz uzyskać dostęp do więcej niż jednej kolumny na raz, możesz:

>>> test = np.arange(9).reshape((3,3))
>>> test
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
>>> test[:,[0,2]]
array([[0, 2],
       [3, 5],
       [6, 8]])
Akavall
źródło
choć oczywiście w tym przypadku nie tylko uzyskujesz dostęp do danych; zwracasz kopię (fantazyjne indeksowanie)
John Greenall
14
test[:,[0,2]]po prostu uzyskuje dostęp do danych, np. test[:, [0,2]] = somethingzmodyfikuje test, a nie utworzy kolejnej tablicy. Ale copy_test = test[:, [0,2]]tak naprawdę tworzy kopię, jak mówisz.
Akavall
3
Stwórz kopię, czy można uzyskać odwołanie, tak jak otrzymuję odwołanie do niektórych kolumn, każda zmiana w tym odwołaniu jest odzwierciedlona w oryginalnej tablicy?
harmands 18.10.16
@ harman786 możesz po prostu ponownie przypisać zmodyfikowaną tablicę do starej.
Tamoghna Chowdhury
Dlaczego test[:,[0,2]]po prostu uzyskuje dostęp do danych, a test[:, [0, 2]][:, [0, 1]]nie? Wydaje się bardzo nieintuicyjne, że zrobienie tego samego ponownie przynosi różne rezultaty.
mapf
65
>>> test[:,0]
array([1, 3, 5])

to polecenie daje wektor wiersza, jeśli po prostu chcesz go zapętlić, jest w porządku, ale jeśli chcesz hstackować z inną tablicą o wymiarze 3xN, będziesz mieć

ValueError: all the input arrays must have same number of dimensions

podczas

>>> test[:,[0]]
array([[1],
       [3],
       [5]])

daje wektor kolumny, dzięki czemu można wykonać operację konkatenacji lub operacji hstack.

na przykład

>>> np.hstack((test, test[:,[0]]))
array([[1, 2, 1],
       [3, 4, 3],
       [5, 6, 5]])
Chmura
źródło
1
indeksowanie działa również z więcej niż kolumną na raz, więc ostatnim przykładem może być test [:, [0,1,0]] lub test [:, [zakres (test.shape [1]) + [0]] ]
lib
5
+1 za określenie [:, [0]] vs [:, 0], aby uzyskać wektor kolumny zamiast wektora wiersza. Dokładnie takie zachowanie, którego szukałem. Również +1 do lib za dodatkową notatkę indeksującą. Ta odpowiedź powinna być na górze z odpowiedzią najwyższą.
dj
1
Ta odpowiedź musi zostać wybrana
Gusev Slava
22

Możesz także transponować i zwrócić wiersz:

In [4]: test.T[0]
Out[4]: array([1, 3, 5])
Hotschke
źródło
Robiłem to przez chwilę, zanim szukałem najszybszego sposobu dostępu do kolumn, zastanawiam się, czy jest to szybsze, wolniejsze, czy po prostu takie samo jak test [:, [0]]
José Chamorro
6

Aby uzyskać kilka niezależnych kolumn, wystarczy:

> test[:,[0,2]]

dostaniesz kolumny 0 i 2

Alberto Perez
źródło
2
Czym to się różni od odpowiedzi Akavall ?
Wszyscy pracownicy są niezbędni
5

Chociaż pytanie zostało udzielone, pozwól mi wspomnieć o kilku niuansach.

Załóżmy, że interesuje Cię pierwsza kolumna tablicy

arr = numpy.array([[1, 2],
                   [3, 4],
                   [5, 6]])

Jak już wiesz z innych odpowiedzi, aby uzyskać go w postaci „wektora wiersza” (tablica kształtu (3,)), używasz krojenia:

arr_c1_ref = arr[:, 1]  # creates a reference to the 1st column of the arr
arr_c1_copy = arr[:, 1].copy()  # creates a copy of the 1st column of the arr

Aby sprawdzić, czy tablica jest widokiem, czy kopią innej tablicy, możesz wykonać następujące czynności:

arr_c1_ref.base is arr  # True
arr_c1_copy.base is arr  # False

patrz ndarray.base .

Oprócz oczywistej różnicy między nimi (modyfikacja arr_c1_refwpłynie arr), liczba kroków bajtów dla przejścia każdego z nich jest inna:

arr_c1_ref.strides[0]  # 8 bytes
arr_c1_copy.strides[0]  # 4 bytes

patrz kroki . Dlaczego to jest ważne? Wyobraź sobie, że masz bardzo dużą tablicę Azamiast arr:

A = np.random.randint(2, size=(10000,10000), dtype='int32')
A_c1_ref = A[:, 1] 
A_c1_copy = A[:, 1].copy()

i chcesz obliczyć sumę wszystkich elementów pierwszej kolumny, tj . A_c1_ref.sum()lub A_c1_copy.sum(). Korzystanie ze skopiowanej wersji jest znacznie szybsze:

%timeit A_c1_ref.sum()  # ~248 µs
%timeit A_c1_copy.sum()  # ~12.8 µs

Wynika to z różnej liczby wspomnianych wcześniej kroków:

A_c1_ref.strides[0]  # 40000 bytes
A_c1_copy.strides[0]  # 4 bytes

Chociaż może się wydawać, że użycie kopii kolumnowych jest lepsze, nie zawsze jest to prawdą, ponieważ wykonanie kopii zajmuje dużo czasu i zajmuje więcej pamięci (w tym przypadku jej utworzenie zajęło mi około 200 µs A_c1_copy). Jednak jeśli potrzebujemy kopii w pierwszej kolejności lub musimy wykonać wiele różnych operacji na konkretnej kolumnie tablicy i nie mamy nic przeciwko poświęceniu pamięci dla szybkości, to zrobienie kopii jest dobrym rozwiązaniem.

W przypadku, gdy jesteśmy zainteresowani pracą głównie z kolumnami, dobrym pomysłem może być utworzenie naszej tablicy w kolejności kolumnowej („F”) zamiast w kolejności rzędnej („C”) (która jest domyślna ), a następnie wykonaj wycinanie jak poprzednio, aby uzyskać kolumnę bez kopiowania:

A = np.asfortranarray(A)  # or np.array(A, order='F')
A_c1_ref = A[:, 1]
A_c1_ref.strides[0]  # 4 bytes
%timeit A_c1_ref.sum()  # ~12.6 µs vs ~248 µs

Teraz wykonanie operacji sumowania (lub dowolnej innej) w widoku kolumny jest znacznie szybsze.

Na koniec pragnę zauważyć, że transpozycja tablicy i stosowanie wycinania wierszy jest tym samym, co użycie wycinania kolumn na oryginalnej tablicy, ponieważ transpozycja odbywa się poprzez zamianę kształtu i kroków oryginalnej tablicy.

A.T[1,:].strides[0]  # 40000
X Æ A-12
źródło
3
>>> test
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])

>>> ncol = test.shape[1]
>>> ncol
5L

Następnie możesz wybrać 2–4 kolumnę w ten sposób:

>>> test[0:, 1:(ncol - 1)]
array([[1, 2, 3],
       [6, 7, 8]])
prochowiec
źródło