C'est ainsi que numpy utilise l'indexation avancée pour diffuser des formes de tableau. Lorsque vous passez un 0
pour le premier index et y
pour le dernier index, numpy diffusera le 0
pour avoir la même forme que y
. L'équivalence suivante est: x[0,:,:,y] == x[(0, 0, 0),:,:,y]
. Voici un exemple
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
Maintenant, comme vous transmettez effectivement deux ensembles d'indices, vous utilisez l'API d'indexation avancée pour former (dans ce cas) des paires d'indices.
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)
]
Qui a une première dimension identique à la longueur de y
. Voilà ce que vous voyez.
Par exemple, regardez un tableau avec 4 dimensions qui sont décrites dans le bloc suivant:
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
a une forme séquentielle vraiment facile à comprendre que nous pouvons maintenant utiliser pour montrer ce qui se passe ...
La première dimension est comme avoir 2 classeurs Excel, la deuxième dimension est comme avoir 3 feuilles dans chaque classeur, la troisième dimension est comme avoir 4 lignes par feuille et la dernière dimension est 5 valeurs pour chaque ligne (ou colonnes par feuille).
En le regardant de cette façon, en demandant x[0,:,:,0]
, c'est le dicton: "dans le premier classeur, pour chaque feuille, pour chaque ligne, donnez-moi la première valeur / colonne."
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]
Mais maintenant, avec l'indexation avancée, nous pouvons penser x[(0,0,0),:,:,y]
à "dans le premier classeur, pour chaque feuille, pour chaque ligne, donnez-moi la y
valeur / colonne. Ok, maintenant faites-le pour chaque valeur de 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]]])
Là où ça devient fou, c'est que numpy diffusera pour correspondre aux dimensions externes du tableau d'index. Donc, si vous voulez faire la même opération que ci-dessus, mais pour les DEUX "classeurs Excel", vous n'avez pas à boucler et à concaténer. Vous pouvez simplement passer un tableau à la première dimension, mais il DOIT avoir une forme compatible.
La transmission d'un entier est diffusée vers y.shape == (3,)
. Si vous voulez passer un tableau comme premier index, seule la dernière dimension du tableau doit être compatible avec y.shape
. C'est-à-dire que la dernière dimension du premier index doit être soit 3 soit 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)
Trouvé une courte explication dans les documents: https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#combining-advanced-and-basic-indexing
Éditer:
À partir de la question d'origine, pour obtenir une ligne de votre sous-découpage souhaité, vous pouvez utiliser x[0][:,:,y]
:
x[0][:,:,y].shape
# returns
(2, 50, 3)
Cependant, si vous essayez d' affecter à ces sous-tranches, vous devez être très prudent que vous regardez une vue de mémoire partagée du tableau d'origine. Sinon, l'affectation ne concernera pas le tableau d'origine, mais une copie.
La mémoire partagée se produit uniquement lorsque vous utilisez un entier ou une tranche pour sous-définir votre tableau, c'est x[:,0:3,:,:]
-à- dire ou x[0,:,:,1:-1]
.
np.shares_memory(x, x[0])
# returns:
True
np.shares_memory(x, x[:,:,:,y])
# returns:
False
Dans votre question d'origine et mon exemple y
n'est ni un entier ni une tranche, donc finira toujours par être attribué à une copie de l'original.
MAIS! Parce que votre tableau pour y
peut être exprimé sous la forme d' une tranche, vous POUVEZ réellement obtenir une vue assignable de votre choix via:
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
Ici, nous utilisons la tranche 0:21:10
pour saisir chaque index qui se trouverait range(0,21,10)
. Nous devons utiliser 21
et non 20
parce que le point d'arrêt est exclu de la tranche, tout comme dans la range
fonction.
Donc, fondamentalement, si vous pouvez construire une tranche qui correspond à vos critères de sous-découpage, vous pouvez faire une affectation.