2015-04-27 5 views
15

Il comportamento della funzione rollaxis numpy mi confonde. Il documentation dice:Motivo per cui il rolagismo intorpidito è così confuso?

Rotolo l'asse specificato all'indietro, fino a quando non si trova in una determinata posizione.

E per il parametro start:

L'asse è rotolato fino a quando non si trova davanti a questa posizione.

Per me, questo è già in qualche modo incoerente.

Ok, dritto esempio in avanti (dalla documentazione):

>>> a = np.ones((3,4,5,6)) 
>>> np.rollaxis(a, 1, 4).shape 
(3, 5, 6, 4) 

L'asse di indice 1 (4) viene arrotolato all'indietro fino a che si trova davanti indice 4.

Ora, quando l'indice start è minore dell'indice axis, abbiamo questo comportamento:

>>> np.rollaxis(a, 3, 1).shape 
(3, 6, 4, 5) 

Invece di spostamento dell'asse all'indice 3 prima di indice 1, si finisce a 1.

Perché è quello? Perché l'asse non viene sempre spostato sull'indice start specificato?

+4

Concordo, il la documentazione (e il comportamento osservato) non corrispondono. Inoltre la documentazione non menziona che si possono usare indici negativi (come con l'indicizzazione di liste python) per contare all'indietro. Sembra che ci sia almeno un problema su GitHub riguardo questo argomento. – PeterE

+0

Correlati: http://stackoverflow.com/q/22583792/1461210 –

+1

Gli ingressi 'transpose 'corrispondenti sono più facili da capire? 'np.transpose (a, [0,2,3,1]). shape' e' np.transpose (a, [0,3,1,2]). shape' – hpaulj

risposta

8

Gran parte della confusione deriva dalla nostra intuizione umana: come pensiamo di spostare un asse. Potremmo specificare un numero di passi di scorrimento (avanti o indietro di 2 passi) o una posizione nella tupla di forma finale o posizione relativa alla forma originale.

Penso che la chiave per capire rollaxis è di concentrarsi sugli slot nella forma originale. L'affermazione più generale che posso venire in mente è:

Rotolo a.shape[axis] alla posizione prima a.shape[start]

before in questo contesto significa lo stesso che nella lista insert(). Quindi è possibile inserire prima della fine.

L'azione di base di rollaxis è:

axes = list(range(0, n)) 
axes.remove(axis) 
axes.insert(start, axis) 
return a.transpose(axes) 

Se axis<start, poi start-=1 per tenere conto per l'azione remove.

I valori negativi sono +=n, quindi rollaxis(a,-2,-3) corrisponde a np.rollaxis(a,2,1). per esempio. a.shape[-3]==a.shape[1]. L'elenco insert consente anche una posizione di inserimento negativa, ma rollaxis non utilizza questa funzione.

Quindi le chiavi capiscono che la coppia di azioni remove/insert e la comprensione transpose(x).

Ho il sospetto che rollaxis sia una versione più intuitiva di transpose.Che lo raggiunga o meno è un'altra domanda.


Lei suggerisce sia omettendo il start-=1 o applicare su tutta la linea

Tralasciando che non modifica i 2 esempi. Ha effetto solo sul caso rollaxis(a,1,4) e axes.insert(4,1) corrisponde a axes.insert(3,1) quando axes è [0,2,3]. Il 1 è ancora posizionato alla fine. La modifica che prova un po ':

np.rollaxis(a,1,3).shape 
# (3, 5, 4, 6) # a.shape[1](4) placed before a.shape[3](6) 

senza la -=1

# transpose axes == [0, 2, 3, 1] 
# (3, 5, 6, 4) # the 4 is placed at the end, after 6 

Se invece -=1 applica sempre

np.rollaxis(a,3,1).shape 
# (3, 6, 4, 5) 

diventa

(6, 3, 4, 5) 

ora esimo e 6 è prima dello 3, che era l'originale a.shape[0]. Dopo il rotolo 3 è il a.shape[1]. Ma questa è una diversa specifica roll.

Si tratta di come è definito start. È una posizione nell'ordine originale o una posizione nell'ordine restituito?


Se si preferisce pensare a start come posizione di indice nella forma finale, non sarebbe più semplice far cadere la parte before e dire 'spostare axis a dest fessura'?

myroll(a, axis=3, dest=0) => (np.transpose(a,[3,0,1,2]) 
myroll(a, axis=1, dest=3) => (np.transpose(a,[0,2,3,1]) 

Basta far cadere il test -=1 potrebbe fare il trucco (Omissione la gestione dei numeri negativi e confini)

def myroll(a,axis,dest): 
    x=list(range(a.ndim)) 
    x.remove(axis) 
    x.insert(dest,axis) 
    return a.transpose(x) 
+0

Una buona spiegazione, tuttavia ritengo che il difetto di questa implementazione sia la distinzione tra il caso "axis = start'. Se questo è stato omesso (o 'start - = 1' per entrambi i casi), il comportamento sarebbe coerente. – Simikolon

+0

Ho modificato la mia risposta per esplorare quelle alternative. – hpaulj

+0

In realtà vedo 'start' come un indice nella lista degli assi. Poiché il numero di assi non cambia, non importa se "start" si riferisce all'originale o all'asse che ne risulta. Fondamentalmente chiamando 'np.rollaxis (a, 3, 1)' dice "Voglio che l'asse dell'indice 3 sia spostato sull'indice 0 (prima di 1)", proprio come nel 'np.rollaxis (a, 1, 3) 'esempio in cui l'asse nell'indice 1 viene spostato nell'indice 2 (prima di 3). – Simikolon

1
a = np.arange(1*2*3*4*5).reshape(1,2,3,4,5) 

np.rollaxis(a,axis,start) 

'asse' è l'indice dell'asse da movimentare a partire dal 0. Nel mio esempio l'asse in posizione 0 è 1.

"start" è l'indice (sempre a partire da 0) dell'asse su cui vorremmo spostare l'asse selezionato in precedenza.

Quindi, se inizio = 2, l'asse in posizione 2 è 3, l'asse Perciò selezionati saranno prima delle 3.

Esempi:

>>> np.rollaxis(a,0,2).shape # the 1 will be before the 3. 

(2, 1, 3, 4, 5) 

>>> np.rollaxis(a,0,3).shape # the 1 will be before the 4. 

(2, 3, 1, 4, 5) 

>>> np.rollaxis(a,1,2).shape # the 2 will be before the 3. 

(1, 2, 3, 4, 5) 

>>> np.rollaxis(a,1,3).shape # the 2 will be before the 4. 

(1, 3, 2, 4, 5) 

Così, dopo il lancio il numero a l'asse prima del tiro sarà posizionato appena prima del numero all'inizio del tiro.

Se pensate a rotoli come questo è molto semplice e ha perfettamente senso, anche se è strano che abbiano scelto di progettarlo in questo modo.

Quindi, cosa succede quando asse e inizio sono uguali?Beh, ovviamente non puoi mettere un numero prima di se stesso, quindi il numero non si muove e l'istruzione diventa un no-op.

Esempi:

>>> np.rollaxis(a,1,1).shape # the 2 can't be moved to before the 2. 

(1, 2, 3, 4, 5) 

>>> np.rollaxis(a,2, 2).shape # the 3 can't be moved to before the 3. 

(1, 2, 3, 4, 5) 

ne dite di spostare l'asse fino alla fine? Bene, non c'è nessun numero dopo la fine, ma è possibile specificare l'inizio come dopo la fine.

Esempio:

>>> np.rollaxis(a,1,5).shape # the 2 will be moved to the end. 

(1, 3, 4, 5, 2) 

>>> np.rollaxis(a,2,5).shape # the 3 will be moved to the end. 

(1, 2, 4, 5, 3) 


>>> np.rollaxis(a,4,5).shape # the 5 is already at the end. 

(1, 2, 3, 4, 5) 
7

NumPy v1.11 e più recenti include una nuova funzione, moveaxis, che mi consiglia di utilizzare al posto di rollaxis (disclaimer:! L'ho scritto). L'asse fonte finisce sempre a destinazione, senza alcuna divertenti problemi off-by-one a seconda se start è maggiore o minore di end:

import numpy as np 

x = np.zeros((1, 2, 3, 4, 5)) 
for i in range(5): 
    print(np.moveaxis(x, 3, i).shape) 

Risultati in:

(4, 1, 2, 3, 5) 
(1, 4, 2, 3, 5) 
(1, 2, 4, 3, 5) 
(1, 2, 3, 4, 5) 
(1, 2, 3, 5, 4)