Ecco come numpy usa l'indicizzazione avanzata per trasmettere forme di array. Quando si passa a 0
per il primo indice e y
per l'ultimo indice, numpy trasmetterà 0
la stessa forma di y
. Il seguente equivalenza vale: x[0,:,:,y] == x[(0, 0, 0),:,:,y]
. ecco un esempio
import numpy as np
x = np.arange(120).reshape(2,3,4,5)
y = np.array([0,2,4])
np.equal(x[0,:,:,y], x[(0, 0, 0),:,:,y]).all()
# returns:
True
Ora, poiché stai effettivamente passando in due set di indici, stai usando l'API di indicizzazione avanzata per formare (in questo caso) coppie di indici.
x[(0, 0, 0),:,:,y])
# equivalent to
[
x[0,:,:,y[0]],
x[0,:,:,y[1]],
x[0,:,:,y[2]]
]
# equivalent to
rows = np.array([0, 0, 0])
cols = y
x[rows,:,:,cols]
# equivalent to
[
x[r,:,:,c] for r, c in zip(rows, columns)
]
Che ha una prima dimensione uguale alla lunghezza di y
. Questo è quello che stai vedendo.
Ad esempio, guarda un array con 4 dimensioni che sono descritte nel prossimo pezzo:
x = np.arange(120).reshape(2,3,4,5)
y = np.array([0,2,4])
# x looks like:
array([[[[ 0, 1, 2, 3, 4], -+ =+
[ 5, 6, 7, 8, 9], Sheet1 |
[ 10, 11, 12, 13, 14], | |
[ 15, 16, 17, 18, 19]], -+ |
Workbook1
[[ 20, 21, 22, 23, 24], -+ |
[ 25, 26, 27, 28, 29], Sheet2 |
[ 30, 31, 32, 33, 34], | |
[ 35, 36, 37, 38, 39]], -+ |
|
[[ 40, 41, 42, 43, 44], -+ |
[ 45, 46, 47, 48, 49], Sheet3 |
[ 50, 51, 52, 53, 54], | |
[ 55, 56, 57, 58, 59]]], -+ =+
[[[ 60, 61, 62, 63, 64],
[ 65, 66, 67, 68, 69],
[ 70, 71, 72, 73, 74],
[ 75, 76, 77, 78, 79]],
[[ 80, 81, 82, 83, 84],
[ 85, 86, 87, 88, 89],
[ 90, 91, 92, 93, 94],
[ 95, 96, 97, 98, 99]],
[[100, 101, 102, 103, 104],
[105, 106, 107, 108, 109],
[110, 111, 112, 113, 114],
[115, 116, 117, 118, 119]]]])
x
ha una forma sequenziale davvero facile da capire che ora possiamo usare per mostrare cosa sta succedendo ...
La prima dimensione è come avere 2 cartelle di lavoro Excel, la seconda dimensione è come avere 3 fogli in ciascuna cartella di lavoro, la terza dimensione è come avere 4 righe per foglio e l'ultima dimensione è 5 valori per ogni riga (o colonne per foglio).
Guardandolo in questo modo, chiedendo x[0,:,:,0]
, è il detto: "nella prima cartella di lavoro, per ogni foglio, per ogni riga, dammi il primo valore / colonna".
x[0,:,:,y[0]]
# returns:
array([[ 0, 5, 10, 15],
[20, 25, 30, 35],
[40, 45, 50, 55]])
# this is in the same as the first element in:
x[(0,0,0),:,:,y]
Ma ora con l'indicizzazione avanzata, possiamo pensare x[(0,0,0),:,:,y]
a "nella prima cartella di lavoro, per ogni foglio, per ogni riga, dammi il y
valore th / colonna. Ok, ora fallo per ogni valore di y
"
x[(0,0,0),:,:,y]
# returns:
array([[[ 0, 5, 10, 15],
[20, 25, 30, 35],
[40, 45, 50, 55]],
[[ 2, 7, 12, 17],
[22, 27, 32, 37],
[42, 47, 52, 57]],
[[ 4, 9, 14, 19],
[24, 29, 34, 39],
[44, 49, 54, 59]]])
Dove impazzisce è che numpy trasmetterà per abbinare le dimensioni esterne della matrice di indice. Quindi, se si desidera eseguire la stessa operazione di cui sopra, ma per ENTRAMBI le "cartelle di lavoro di Excel", non è necessario eseguire il ciclo e concatenare. Puoi semplicemente passare un array alla prima dimensione, ma esso DEVE avere una forma compatibile.
Il passaggio di un numero intero viene trasmesso a y.shape == (3,)
. Se si desidera passare un array come primo indice, solo l'ultima dimensione dell'array deve essere compatibile con y.shape
. Vale a dire, l'ultima dimensione del primo indice deve essere 3 o 1.
ix = np.array([[0], [1]])
x[ix,:,:,y].shape
# each row of ix is broadcast to length 3:
(2, 3, 3, 4)
ix = np.array([[0,0,0], [1,1,1]])
x[ix,:,:,y].shape
# this is identical to above:
(2, 3, 3, 4)
ix = np.array([[0], [1], [0], [1], [0]])
x[ix,:,:,y].shape
# ix is broadcast so each row of ix has 3 columns, the length of y
(5, 3, 3, 4)
Ho trovato una breve spiegazione nei documenti: https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#combining-advanced-and-basic-indexing
Modificare:
Dalla domanda originale, per ottenere una riga del sottotitolo desiderato, è possibile utilizzare x[0][:,:,y]
:
x[0][:,:,y].shape
# returns
(2, 50, 3)
Tuttavia, se stai cercando di assegnare a questi sottotitoli, è necessario fare molta attenzione a guardare una vista di memoria condivisa dell'array originale. In caso contrario, l'assegnazione non sarà dell'array originale, ma di una copia.
La memoria condivisa si verifica solo quando si utilizza un numero intero o una porzione per sottoinsieme dell'array, ovvero x[:,0:3,:,:]
o x[0,:,:,1:-1]
.
np.shares_memory(x, x[0])
# returns:
True
np.shares_memory(x, x[:,:,:,y])
# returns:
False
Sia nella tua domanda originale che nel mio esempio y
non è né un int né una sezione, quindi finirò sempre per assegnare una copia dell'originale.
MA! Perché il vostro array per y
può essere espressa come una fetta, è POSSIBILE effettivamente ottenere una visione assegnabile della matrice tramite:
x[0,:,:,0:21:10].shape
# returns:
(2, 50, 3)
np.shares_memory(x, x[0,:,:,0:21:10])
# returns:
True
# actually assigns to the original array
x[0,:,:,0:21:10] = 100
Qui usiamo la sezione 0:21:10
per afferrare ogni indice in cui si troverebbe range(0,21,10)
. Dobbiamo usare 21
e non 20
perché il punto di arresto è escluso dalla sezione, proprio come nel filerange
funzione.
Quindi, fondamentalmente, se riesci a costruire una sezione che si adatta ai tuoi criteri di sottotitolo, puoi fare un incarico.