Come accedere alla colonna di un array multidimensionale NumPy?


463

Supponiamo di avere:

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

test[i]mi porta con la linea dell'array (ad es [1, 2].). Come posso accedere al esima colonna? (ad es [1, 3, 5].). Inoltre, sarebbe un'operazione costosa?

Risposte:


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

Allo stesso modo,

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

ti consente di accedere alle righe. Questo è trattato nella Sezione 1.4 (Indicizzazione) del riferimento NumPy . Questo è veloce, almeno nella mia esperienza. È certamente molto più veloce dell'accesso a ciascun elemento in un ciclo.


11
Questo crea una copia, è possibile ottenere un riferimento, come se avessi un riferimento a una colonna, ogni cambiamento in questo riferimento si riflette nella matrice originale.
danneggia il

@harmands Questo non crea una copia, crea una vista.
risciacquo

69

E se si desidera accedere a più di una colonna alla volta, è possibile:

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

anche se ovviamente in questo caso non stai solo accedendo ai dati; stai restituendo una copia (indicizzazione elaborata)
John Greenall,

14
test[:,[0,2]]semplicemente accede ai dati, ad esempio, test[:, [0,2]] = somethingmodifica il test e non crea un altro array. Ma copy_test = test[:, [0,2]]in effetti crea una copia come dici tu.
Akavall,

3
Questo crea una copia, è possibile ottenere un riferimento, come se avessi un riferimento ad alcune colonne, qualsiasi cambiamento in questo riferimento si riflette nella matrice originale?
danneggia il

@ harman786 potresti semplicemente riassegnare l'array modificato a quello vecchio.
Tamoghna Chowdhury,

Perché test[:,[0,2]]accede semplicemente ai dati mentre test[:, [0, 2]][:, [0, 1]]no? Sembra poco intuitivo che fare di nuovo la stessa cosa abbia un risultato diverso.
mapf

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

questo comando ti dà un vettore di riga, se vuoi solo passare su di esso, va bene, ma se vuoi hstack con qualche altro array con dimensione 3xN, avrai

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

mentre

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

ti dà un vettore di colonna, in modo da poter eseguire operazioni concatenate o hstack.

per esempio

>>> np.hstack((test, test[:,[0]]))
array([[1, 2, 1],
       [3, 4, 3],
       [5, 6, 5]])

1
l'indicizzazione funziona anche con più di una colonna alla volta, quindi l'ultimo esempio potrebbe essere test [:, [0,1,0]] o test [:, [range (test.shape [1]) + [0]] ]
lib

5
+1 per specificare [:, [0]] vs [:, 0] per ottenere un vettore di colonna anziché un vettore di riga. Esattamente il comportamento che stavo cercando. Anche +1 su lib per la nota di indicizzazione aggiuntiva. Questa risposta dovrebbe essere proprio lì con la risposta migliore.
dhj

1
Questa risposta deve essere scelta
Gusev Slava,

22

È inoltre possibile trasporre e restituire una riga:

In [4]: test.T[0]
Out[4]: array([1, 3, 5])

Lo sto facendo da un po 'prima di cercare un modo più veloce per accedere alle colonne, mi chiedo se questo sia più veloce, più lento o uguale a test [:, [0]]
José Chamorro


5

Sebbene alla domanda sia stata data una risposta, vorrei menzionare alcune sfumature.

Supponiamo che tu sia interessato alla prima colonna dell'array

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

Come già sapete da altre risposte, per ottenerlo sotto forma di "vettore riga" (matrice di forme (3,)), usate l'affettamento:

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

Per verificare se un array è una vista o una copia di un altro array è possibile effettuare le seguenti operazioni:

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

vedi ndarray.base .

Oltre all'ovvia differenza tra i due (la modifica arr_c1_refinfluirà arr), il numero di byte-passi per attraversarli è diverso:

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

vedere i passi . Perché questo è importante? Immagina di avere un array molto grande al Aposto di arr:

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

e vuoi calcolare la somma di tutti gli elementi della prima colonna, ovvero A_c1_ref.sum()o A_c1_copy.sum(). L'uso della versione copiata è molto più veloce:

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

Ciò è dovuto al diverso numero di passi menzionati prima:

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

Anche se potrebbe sembrare che l'uso delle copie delle colonne sia migliore, non è sempre vero per il fatto che fare una copia richiede tempo e utilizza più memoria (in questo caso mi ci sono voluti circa 200 µs per creare il A_c1_copy). Tuttavia, se abbiamo bisogno della copia in primo luogo, o dobbiamo fare molte operazioni diverse su una colonna specifica dell'array e siamo d'accordo con il sacrificare memoria per la velocità, quindi fare una copia è la strada da percorrere.

Nel caso in cui siamo interessati a lavorare principalmente con le colonne, potrebbe essere una buona idea creare il nostro array in ordine di colonna maggiore ('F') anziché nell'ordine di riga maggiore ('C') (che è l'impostazione predefinita ), quindi esegui lo slicing come prima per ottenere una colonna senza copiarla:

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

Ora, eseguire l'operazione di somma (o qualsiasi altra) su una vista a colonne è molto più veloce.

Vorrei infine notare che trasporre un array e usare il taglio di riga è lo stesso che usare il taglio di colonna sull'array originale, perché il recepimento avviene semplicemente scambiando la forma e i passi dell'array originale.

A.T[1,:].strides[0]  # 40000

3
>>> test
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])

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

Quindi puoi selezionare la seconda - quarta colonna in questo modo:

>>> test[0:, 1:(ncol - 1)]
array([[1, 2, 3],
       [6, 7, 8]])
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.