Numpy index slice senza perdere le informazioni sulla dimensione


98

Sto usando numpy e desidero indicizzare una riga senza perdere le informazioni sulla dimensione.

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

In questo esempio xslice è ora 1 dimensione, ma voglio che sia (1,10). In R, userei X [10,:, drop = F]. C'è qualcosa di simile in numpy. Non sono riuscito a trovarlo nella documentazione e non ho visto una domanda simile.

Grazie!

Risposte:


59

Probabilmente è più facile da fare x[None, 10, :]o in modo equivalente (ma più leggibile) x[np.newaxis, 10, :].

Per quanto riguarda il motivo per cui non è l'impostazione predefinita, personalmente, trovo che avere costantemente array con dimensioni singole diventa fastidioso molto rapidamente. Immagino che gli sviluppatori numpy la pensassero allo stesso modo.

Inoltre, numpy gestisce molto bene gli array di trasmissione, quindi di solito ci sono poche ragioni per mantenere la dimensione dell'array da cui proviene lo slice. Se l'hai fatto, allora cose come:

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

o non funzionerebbe o sarebbe molto più difficile da implementare.

(O almeno questa è la mia ipotesi sul ragionamento del numpy dev dietro la caduta delle informazioni sulla dimensione durante il taglio)


6
@Lisa: x[None, 10]farà quello che vuoi.
nought101

Sì. Metti le tue Nones vicino ai fiocchi che stai tagliando.
Mad Physicist

1
Nell'esempio mancano parentesi aggiuntive per la tupla nell'assegnazione a b; dovrebbe essere b = np.zeros((100,10)).
Jerzy

Qual è il motivo per utilizzare 3 indici in totale invece di solo due? Voglio dire X[10,None](usando il tuo codice come esempio).
greenoldman

8
" di solito ci sono poche ragioni per mantenere la dimensione dell'array " ... Beh, certamente, completamente e completamente rovinerà la moltiplicazione della matrice ( np.matmul()o@ ). Sono appena stato bruciato da questo.
Jean-François Corbett

89

Un'altra soluzione è fare

X[[10],:]

o

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

La dimensionalità di un array viene preservata quando l'indicizzazione viene eseguita da un elenco (o un array) di indici. Questo è bello perché ti lascia la scelta tra mantenere la dimensione e spremere.


2
Questo copia i dati dell'array
Per

Non è sempre così. Vedi: x = np.array([[1,2,3,4]]) se poi lo tagli con x[[0],[1,2]] ottieni il monodimensionale La array([2, 3]) mia opinione è che quando selezioni i vettori di colonne o righe è meglio rendere la fetta semplice e quindi usarla np.reshape, Quindi nel mio esempio sarebbenp.reshape(x[0,[1,2]],[1,2])
Alexander

1
altri, essere consapevoli di un punto e virgola alla fine - è importante, X[[10]]sarebbe interpretato come X[10]e la forma sarà più piccola; allo stesso modo, X[[10, 20]] == X[10, 20]e la forma è ancora più piccola
Ben Usman

1
Attenzione : non mescolare questo modo di indicizzazione con l'indicizzazione di interi! Se tu avessi adi forma (10, 20, 30), allora a[0, :, [0]]avrai forma (1, 20), no (20, 1), perché in quest'ultimo vengono trasmessi gli indici a a[[0], :, [0]]cui spesso non è proprio quello che ti aspetti! Considerando che a[0, :, :1]ti darà (20, 1)come previsto. Inoltre, vedere il commento sopra per il caso limite strano con indice singolo. Nel complesso, sembra che questo metodo abbia troppi casi limite.
Ben Usman

30

Ho trovato alcune soluzioni ragionevoli.

1) utilizzo numpy.take(X,[10],0)

2) usa questa strana indicizzazione X[10:11:, :]

Idealmente, questo dovrebbe essere il valore predefinito. Non ho mai capito perché le dimensioni vengano mai eliminate. Ma questa è una discussione per numpy ...


1
Le 'dimensioni' vengono eliminate durante l'indicizzazione degli elenchi Python alist[0]e mantenute durante la suddivisione in sezioni.
hpaulj

4
L'opzione 2 (che può essere scritta come slice(n, n+1)per l'estrazione dell'indice n) dovrebbe essere la risposta accettata, poiché è l'unica che si estende naturalmente al caso n-dimensionale.
norok2

L'opzione 2 sembra essere in grado di essere scritta come X[10:11, :]in Python 3.7.5 (cioè senza i due punti extra dopo l'11)
Joe

6

Ecco un'alternativa che mi piace di più. Invece di indicizzare con un singolo numero, indicizzare con un intervallo. Cioè, usa X[10:11,:]. (Nota che 10:11non include 11).

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

Questo rende facile capire anche con più dimensioni, senza Nonegiocoleria e capire quale asse usare quale indice. Inoltre, non è necessario eseguire una contabilità aggiuntiva per quanto riguarda la dimensione dell'array, solo i:i+1per quelli iche avresti usato nell'indicizzazione regolare.

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)


0

Ciò è particolarmente fastidioso se stai indicizzando da un array che potrebbe essere di lunghezza 1 in fase di esecuzione. In questo caso, c'è np.ix_:

some_array[np.ix_(row_index,column_index)]
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.