Wie greife ich auf die i-te Spalte eines mehrdimensionalen NumPy-Arrays zu?

463

Angenommen, ich habe:

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

test[i]holt mir die i-te Zeile des Arrays (zB [1, 2]). Wie kann ich auf die i-te Spalte zugreifen ? (zB [1, 3, 5]). Wäre dies auch eine teure Operation?

lpl
quelle

Antworten:

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

Ähnlich,

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

Ermöglicht den Zugriff auf Zeilen. Dies wird in Abschnitt 1.4 (Indexierung) der NumPy-Referenz behandelt . Das geht schnell, zumindest nach meiner Erfahrung. Es ist sicherlich viel schneller als auf jedes Element in einer Schleife zuzugreifen.

mtrw
quelle
11
Wenn Sie eine Kopie erstellen, ist es möglich, eine Referenz abzurufen, so wie ich eine Referenz auf eine Spalte erhalte. Jede Änderung dieser Referenz wird im ursprünglichen Array wiedergegeben.
Harmands
@harmands Hiermit wird keine Kopie erstellt, sondern eine Ansicht.
Rinspy
69

Wenn Sie auf mehrere Spalten gleichzeitig zugreifen möchten, können Sie Folgendes tun:

>>> 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
quelle
In diesem Fall greifen Sie natürlich nicht nur auf die Daten zu. Sie geben eine Kopie zurück (ausgefallene Indexierung)
John Greenall
14
test[:,[0,2]]Nur Zugriff auf die Daten, z. B. test[:, [0,2]] = somethingwürde den Test ändern und kein weiteres Array erstellen. Erstellt copy_test = test[:, [0,2]]aber tatsächlich eine Kopie, wie Sie sagen.
Akavall
3
Wenn Sie eine Kopie erstellen, ist es möglich, eine Referenz zu erhalten, wie ich eine Referenz auf einige Spalten erhalte. Jede Änderung dieser Referenz spiegelt sich im ursprünglichen Array wider.
Harmands
@ harman786 Sie können das geänderte Array einfach dem alten neu zuweisen.
Tamoghna Chowdhury
Warum greift man test[:,[0,2]]einfach auf die Daten zu, während test[:, [0, 2]][:, [0, 1]]dies nicht der Fall ist? Es scheint sehr unintuitiv zu sein, dass es ein anderes Ergebnis ist, dasselbe noch einmal zu tun.
mapf
65
>>> test[:,0]
array([1, 3, 5])

Dieser Befehl gibt Ihnen einen Zeilenvektor. Wenn Sie nur eine Schleife darüber ausführen möchten, ist dies in Ordnung. Wenn Sie jedoch mit einem anderen Array mit der Dimension 3xN stapeln möchten, haben Sie einen

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

während

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

gibt Ihnen einen Spaltenvektor, damit Sie verketten oder stapeln können.

z.B

>>> np.hstack((test, test[:,[0]]))
array([[1, 2, 1],
       [3, 4, 3],
       [5, 6, 5]])
Wolke
quelle
1
Die Indizierung funktioniert auch mit mehr als einer Spalte pro Zeit, sodass das letzte Beispiel test [:, [0,1,0]] oder test [:, [range (test.shape [1]) + [0]] sein kann. ]
lib
5
+1 für die Angabe von [:, [0]] vs [:, 0], um einen Spaltenvektor anstelle eines Zeilenvektors zu erhalten. Genau das Verhalten, das ich gesucht habe. Auch +1 bis lib für die zusätzliche Indexnotiz. Diese Antwort sollte genau dort oben mit der Top-Antwort sein.
Dhj
1
Diese Antwort muss gewählt werden
Gusev Slava
22

Sie können auch eine Zeile transponieren und zurückgeben:

In [4]: test.T[0]
Out[4]: array([1, 3, 5])
Hotschke
quelle
Ich habe dies eine Weile getan, bevor ich nach einem schnellsten Weg gesucht habe, um auf Spalten zuzugreifen. Ich frage mich, ob dies schneller, langsamer oder genauso ist wie Test [:, [0]]
José Chamorro
6

Um mehrere und unabhängige Spalten zu erhalten, gehen Sie einfach wie folgt vor:

> test[:,[0,2]]

Sie erhalten die Spalten 0 und 2

Alberto Perez
quelle
2
Wie unterscheidet sich das von Akavalls Antwort ?
Alle Arbeiter sind wesentlich
5

Obwohl die Frage beantwortet wurde, möchte ich einige Nuancen erwähnen.

Angenommen, Sie interessieren sich für die erste Spalte des Arrays

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

Wie Sie bereits aus anderen Antworten wissen (3,), verwenden Sie das Schneiden , um es in Form eines "Zeilenvektors" (Array of Shape ) zu erhalten:

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

Gehen Sie wie folgt vor, um zu überprüfen, ob ein Array eine Ansicht oder eine Kopie eines anderen Arrays ist:

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

siehe ndarray.base .

Neben dem offensichtlichen Unterschied zwischen den beiden (die Änderung arr_c1_refwirkt sich aus arr) ist die Anzahl der Byte-Schritte zum Durchlaufen jedes einzelnen von ihnen unterschiedlich:

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

siehe Schritte . Warum ist das wichtig? Stellen Sie sich vor, Sie haben ein sehr großes Array Aanstelle von arr:

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

und Sie möchten die Summe aller Elemente der ersten Spalte berechnen, dh A_c1_ref.sum()oder A_c1_copy.sum(). Die Verwendung der kopierten Version ist viel schneller:

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

Dies ist auf die unterschiedliche Anzahl der zuvor genannten Schritte zurückzuführen:

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

Obwohl es den Anschein hat, dass die Verwendung von Spaltenkopien besser ist, trifft dies nicht immer zu, da das Erstellen einer Kopie Zeit in Anspruch nimmt und mehr Speicher benötigt (in diesem Fall habe ich ca. 200 µs benötigt, um die zu erstellen A_c1_copy). Wenn wir jedoch die Kopie an erster Stelle benötigen oder viele verschiedene Operationen an einer bestimmten Spalte des Arrays ausführen müssen und es uns recht ist, Speicher für Geschwindigkeit zu opfern, ist das Erstellen einer Kopie der richtige Weg.

Für den Fall, dass wir hauptsächlich mit Spalten arbeiten möchten, ist es möglicherweise eine gute Idee, unser Array in der Reihenfolge Spalten-Major ('F') anstelle der Reihenfolge Zeilen-Major ('C') (die Standardeinstellung) zu erstellen ) und schneiden Sie dann wie zuvor, um eine Spalte zu erhalten, ohne sie zu kopieren:

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

Das Ausführen der Summenoperation (oder einer anderen) in einer Spaltenansicht ist jetzt viel schneller.

Abschließend möchte ich darauf hinweisen, dass das Transponieren eines Arrays und das Verwenden des Zeilen-Slicing mit dem Spalten-Slicing des ursprünglichen Arrays identisch ist, da das Transponieren nur durch Vertauschen der Form und der Schritte des ursprünglichen Arrays erfolgt.

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

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

Dann können Sie die 2. - 4. Spalte folgendermaßen auswählen:

>>> test[0:, 1:(ncol - 1)]
array([[1, 2, 3],
       [6, 7, 8]])
Mac
quelle