Skip to article frontmatterSkip to article content
import numpy as np

contenu de ce notebook (notebook optionnel)

on a vu jusqu’ici comment indexer un tableau (quand on écrit valeurs[indices]):

ce que nous appelons ici indexation avancée,
c’est la possibilité d’indexer un tableau avec .. un ou plusieurs autres tableaux d’entiers
c’est-à-dire d’écrire array1[array2] ou encore array1[(array2, array3)]

valeurs en dimension 1

valeurs_d1 = 10 * np.arange(5)
valeurs_d1
array([ 0, 10, 20, 30, 40])

voyons le cas le plus simple, de forme array1[array2]

on va pouvoir indexer valeurs par n’importe quel tableau qui ne contient que des entiers entre 0 et 4
(parce qu’ils seront interprétés comme des indices dans valeurs qui est de taille 5)

et le résultat de valeurs[indices] va être un tableau de la même forme qu’indices
et qui contiendra les valeurs[indice] pour chaque case indice de indices

c’est donc en quelque sorte la version vectorisée de l’indexation par un entier...

# par exemple si indices est un vecteur, on récupère un vecteur
indices = np.array([0, 2, 3, 1, 3, 1, 2, 0, 3, 2, 3])

valeurs_d1[indices]
array([ 0, 20, 30, 10, 30, 10, 20, 0, 30, 20, 30])
# par exemple, si le tableau d'indices est un tableau carré
# on récupère un tableau carré

indices = np.array([[2, 2],
                    [2, 2]])

# à votre avis on obtient quoi ?
valeurs_d1[indices]
array([[20, 20], [20, 20]])

donc si on essaie de formaliser un peu, lorsque valeurs est de dimension 1

valeurs[indices] aura un sens si

valeurs en dimension 2

valeurs_d2 = np.arange(4)+10*np.arange(4).reshape((4, 1))
valeurs_d2
array([[ 0, 1, 2, 3], [10, 11, 12, 13], [20, 21, 22, 23], [30, 31, 32, 33]])

c’est bien sûr la même logique
sauf que cette fois on va avoir envie de .. passer deux tableaux d’indices, puisque valeurs est de dimension 2

avec deux indices de dim 1

indices_i = np.array([1, 2, 0, 3])
indices_j = np.array([0, 2, 1, 3])
valeurs_d2[indices_i, indices_j]
array([10, 22, 1, 33])

avec deux indices de dim 2

bien sûr on peut aussi utiliser des indices de formes en dimensions supérieures

indices_i = np.array([[0, 1],
                      [2, 2]])
indices_j = np.array([[0, 0],
                      [3, 3]])
valeurs_d2[indices_i, indices_j]
array([[ 0, 10], [23, 23]])

avec un seul indice

on peut même ne donner qu’un seul indice !

souvenez-vous, dans le cas hyper simple où vous avez un tableau de 2 dimension et que vous écrivez array[2], vous récupérez la deuxième ligne

ici ça va être pareil: le résultat a une dimension de plus que le tableau d’indices, pour pouvoir ranger à chaque fois toute la ligne valeurs[i]

valeurs_d2
array([[ 0, 1, 2, 3], [10, 11, 12, 13], [20, 21, 22, 23], [30, 31, 32, 33]])
indices_i = np.array([[0, 2],
                      [1, 3]])

avant d’exécuter la prochaine cellule, essayez de calculer mentalement sa forme

si on avait donné deux indices, on aurait obtenu un tableau carré 2x2 mais comme il manque une dimension, à chaque coordonnée (i, j) dans le tableau d’indices, on va récupérer une ligne (qui dans notre tableau de valeurs est de longueur 4)

donc le résultat est de forme ...

r = valeurs_d2[indices_i]
r
array([[[ 0, 1, 2, 3], [20, 21, 22, 23]], [[10, 11, 12, 13], [30, 31, 32, 33]]])
# du coup on 'ajoute' une dimension 4 au résultat

print("si on faisait une indexation complète on obtiendrait", indices_i.shape)
print("l'indexation partielle nous donne ici", r.shape)
si on faisait une indexation complète on obtiendrait (2, 2)
l'indexation partielle nous donne ici (2, 2, 4)

exemple: une colormap

c’est cette technique que nous avons utilisée dans le TP ‘image-2’, pour coder la fonction patchwork

imaginons qu’on a en entrée 5 couleurs (en comptant la couleur de remplissage);
et qu’on doit remplir un rectangle de 2 x 3 patches

et faisons pour commencer abstraction de la taille de chaque patch

colormap = np.array([
    [255, 0, 0],     # 'red'
    [0, 255, 0],     # 'green'
    [0, 0, 255],     # 'blue'
    [0, 255, 255],   # 'cyan'
    [127, 127, 127], # 'grey background'
])
pattern = np.array([
    [0, 1, 2],
    [3, 4, 4],
])
import matplotlib.pyplot as plt
plt.imshow(colormap[pattern]);
<Figure size 640x480 with 1 Axes>

si on prend en compte la taille des patches, le tableau pattern devient un peu plus compliqué, mais c’est toujours le même principe :

pattern2 = np.array([
    [0, 0, 1, 1, 2, 2],
    [0, 0, 1, 1, 2, 2],
    [3, 3, 4, 4, 4, 4],
    [3, 3, 4, 4, 4, 4],
])
plt.imshow(colormap[pattern2]);
<Figure size 640x480 with 1 Axes>