UKOnline

Masque

Concernant l'accès aux éléments d'un tableau, on peut aller plus loin que les techniques vues à la section précédente. On pourrait indiquer, pour chaque élément d'un tableau, si on veut l'extraire ou non. Pour ce faire, on va devoir utiliser un tableau de booléens, appelé masque, avec exactement la même taille et la même forme que le tableau dont on veut extraire des éléments.

Tableau de booléens

Jusqu'à ici, les tableaux multidimensionnels que l'on a pu voir étaient constitués de nombres entiers, flottants ou complexes. On peut également créer des tableaux dont les valeurs sont des booléens :

Ces instructions créent donc un tableau dont les dimensions sont $(2, 3)$ :

[[ True False  True]
 [False False  True]]

Une autre façon de construire un tableau de booléens consiste à utiliser des opérateurs booléens de comparaison avec des tableaux multidimensionnels. Voici un exemple d'une telle construction :

Le tableau créé par l'expression data > 2 possède exactement le même nombre d'éléments que data et les mêmes dimensions. Ses éléments valent True ou False, selon que l'élément à la même position dans le tableau data est strictement plus grand que $2$ ou non :

[[-1  4  0]
 [-3  2  1]]
[[False  True False]
 [False False False]]

Expression complexe

L'expression utilisée pour créer un tableau de booléens à partir d'un tableau de données peut combiner plusieurs opérateurs, tant que cela reste bel et bien une expression booléenne. On peut, par exemple, identifier tous les éléments pairs d'un tableau comme suit :

On se retrouve donc avec un tableau de booléens avec des True aux positions des éléments pairs du tableau data, et des False ailleurs. Le résultat de l'exécution est :

[[False  True  True]
 [False  True False]]

Les opérations possibles sur des tableaux sont détaillées à la section 2.7.

Opérateur booléen

Enfin, on peut combiner des expressions booléennes avec des opérateurs logiques (NON, ET et OU). Ils ne sont pas représentés par les mots réservés not, and et or comme en Python « classique », mais par les opérateurs ~, & et |. Voici un exemple avec un OU logique :

On identifie donc les éléments soit strictement plus grand que $2$, soit strictement plus petit que $-2$ :

[[False  True False]
 [ True False False]]

Application de masque

Une fois un tableau de booléens créé, on peut l'utiliser comme indice pour accéder aux éléments d'un tableau. Dans ce cas, le tableau de booléens est utilisé comme un masque. Voici, par exemple, comment on peut extraire les valeurs paires d'un tableau multidimensionnel :

Dans ce cas, le résultat est un tableau unidimensionnel qui contient tous les éléments de data pour lesquels le tableau de booléens utilisé comme indice vaut True. Dans cet exemple, il y a trois éléments du tableau data qui sont pairs :

[4 0 2]

Cette opération, appelée application d'un masque, est illustrée par la figure 6. C'est comme si on plaçait le tableau de booléens devant le tableau de données et qu'on ne gardait que les éléments pour lesquels la valeur du masque vaut True (c'est un peu comme si on plaçait une carte perforée devant le tableau, pour regarder à travers les trous).

Application d'un masque
Appliquer un masque à un tableau permet d'en extraire un ensemble d'éléments qui satisfont une condition, représentée par un tableau de booléens typiquement construit à partir d'une condition.

Si le tableau de booléens utilisé comme indice est de dimension plus petite que le tableau dont on veut extraire des données, on va pouvoir sélectionner plusieurs éléments avec un seul True. Si on reprend le tableau créé précédemment, on peut, par exemple, sélectionner uniquement la seconde « ligne » comme suit :

Dans ce cas, le résultat est un tableau à deux dimensions qui contient la première « ligne » de data :

[[-3  2  1]]

Contrairement à l'extraction d'un sous-tableau avec une opération de slicing simple, les tableaux qui sont le résultat de l'application d'un masque sont toujours des copies.

Un deuxième type d'opération est la multiplication par un masque. Il remplace par zéro tous les éléments situés à des positions où un masque est vrai. Supprimons, par exemple, les valeurs négatives de data :

Le masque permet d'identifier tous les éléments négatifs. Ensuite, on multiplie data par l'inverse du masque (obtenu avec l'opérateur NON logique) pour ne garder que les valeurs positives du tableau :

[[0 4 0]
 [0 2 1]]

Recherche

On peut aussi vouloir connaitre les indices des éléments qui satisfont une condition. Pour cela, il suffit d'utiliser la fonction where qui prend en paramètre la condition, sous forme d'un tableau de booléens. Retrouvons, par exemple, les indices des valeurs négatives du tableau data :

La fonction where renvoie un tuple avec deux listes d'indices, puisque le tableau data a deux dimensions. Comme il y a trois valeurs négatives, chacune des deux listes aura trois éléments :

(array([0, 0, 1]), array([0, 2, 0]))

Les trois valeurs négatives se trouvent donc aux positions $(0, 0)$, $(0, 2)$ et $(1, 0)$ dans le tableau : il s'agit des éléments $-1$, $0$ et $-3$. Notez que ce tuple de listes d'indices peut directement être utilisé avec l'opérateur d'accès pour extraire ces valeurs depuis le tableau :

L'exécution de cette instruction donne bel et bien le résultat attendu :

[-1  0 -3]

On peut également utiliser la fonction nonzero à la place de la fonction where. Celle-ci renvoie un tuple de tableaux d'indices, un par dimension, localisant les éléments qui sont différents de zéro. Dans le cas d'un tableau de booléens, la fonction nonzero identifie donc les True. Il est recommandé d'utiliser la fonction nonzero, la fonction where telle qu'utilisée pour le moment se contentant d'appeler nonzero. On aurait donc plutôt dû écrire l'instruction suivante :

On se rend vite compte de toute la puissance des masques, permettant d'extraire d'un tableau les éléments qui satisfont une condition, ou les positions de ces derniers. En combinant tout ce qu'on a vu jusqu'à présent, on peut même aller remplacer les éléments négatifs du tableau data par leurs valeurs absolues ! Voici comment :

Le tableau neg contient donc un tableau unidimensionnel avec tous les éléments négatifs de data. On multiplie ensuite tous les éléments de ce tableau par $-1$, les rendant ainsi positifs. Ensuite, on va les replacer au bon endroit dans data, en ne modifiant que les éléments dont les positions sont dans ind. Le résultat est bien celui attendu :

[[1 4 0]
 [3 2 1]]

Remplacement

Enfin, terminons cette section avec une variante de la fonction where, pas remplaçable par la fonction nonzero. On peut, en effet, combiner la recherche d'éléments dans un tableau et le remplacement de ces derniers, en une seule opération :

La fonction where construit cette fois-ci un nouveau tableau, de même taille et avec les mêmes dimensions que data, mais dont les éléments sont soit ceux de data, soit ceux de data * -1, en fonction de la valeur de la condition. On peut comparer cette opération avec l'instruction if compacte de Python (on aurait écrit data * -1 if data <= 0 else data en Python).

Dans cet exemple, on remplace donc les éléments négatifs par leur valeur absolue (en les multipliant par $-1$) et on ne touche pas aux autres éléments. On refait donc la même chose que précédemment, mais de manière bien plus compacte. Le résultat attendu est bien celui obtenu suite à l'exécution de cette instruction :

[[1 4 0]
 [3 2 1]]

Ici, dans cet exemple, on n'a modifié les éléments du tableau que dans l'un des deux cas, et on a gardé les éléments originaux dans l'autre cas. Lorsque c'est ce que l'on veut faire, on n'a pas besoin de passer par la fonction where et on peut se contenter de putmask. Cette fonction permet de juste remplacer les éléments qui satisfont une condition. L'exemple précédent se réécrit donc comme suit :

Comme on peut le constater, il y a néanmoins une différence majeure entre les deux fonctions. La fonction where crée un nouveau tableau tandis que la fonction putmask fait son remplacement directement sur le tableau cible. Selon la situation, il faudra donc d'abord faire une copie ou alors utiliser la fonction adéquate.