Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Licence CC BY-NC-ND Thierry Parmentelat & Arnaud Legout Inria - UCA

Nous allons voir dans ce complément comment créer des tableaux en plusieurs dimensions et manipuler la forme (shape) des tableaux.

import numpy as np

Un exemple

Nous avons vu précédemment comment créer un tableau numpy de dimension 1 à partir d’un simple itérable, nous allons à présent créer un tableau à 2 dimensions, et pour cela nous allons utiliser une liste imbriquée :

d2 = np.array([[11, 12, 13], [21, 22, 23]])
d2
array([[11, 12, 13], [21, 22, 23]])

Ce premier exemple va nous permettre de voir les différents attributs de tous les tableaux numpy.

L’attribut shape

Tous les tableaux numpy possèdent un attribut shape qui retourne, sous la forme d’un tuple, les dimensions du tableau :

# la forme (les dimensions) du tableau
d2.shape
(2, 3)

Dans le cas d’un tableau en 2 dimensions, cela correspond donc à lignes x colonnes.

On peut facilement changer de forme

Comme on l’a vu dans la vidéo, un tableau est en fait une vue vers un bloc de données. Aussi il est facile de changer la dimension d’un tableau - ou plutôt, de créer une autre vue vers les mêmes données :

# l'argument qu'on passe à reshape est le tuple
# qui décrit la nouvelle *shape*
v2 = d2.reshape((3, 2))
v2
array([[11, 12], [13, 21], [22, 23]])

Et donc, ces deux tableaux sont deux vues vers la même zone de données ; ce qui fait qu’une modification sur l’un se répercute dans l’autre :

# je change un tableau
d2[0][0] = 100
d2
array([[100, 12, 13], [ 21, 22, 23]])
# ça se répercute dans l'autre
v2
array([[100, 12], [ 13, 21], [ 22, 23]])

Les attributs liés à la forme

Signalons par commodité les attributs suivants, qui se dérivent de shape :

# le nombre de dimensions
d2.ndim
2
# vrai pour tous les tableaux
len(d2.shape) == d2.ndim
True
# le nombre de cellules
d2.size
6
# vrai pour tous les tableaux
# une façon compliquée de dire
# une chose toute simple :
# la taille est le produit
# des dimensions
from operator import mul
from functools import reduce
d2.size == reduce(mul, d2.shape, 1)
True

Lorsqu’on utilise reshape, il faut bien sûr que la nouvelle forme soit compatible :

try:
    d2.reshape((3, 4))
except Exception as e:
    print(f"OOPS {type(e)} {e}")
OOPS <class 'ValueError'> cannot reshape array of size 6 into shape (3,4)

Dimensions supérieures

Vous pouvez donc deviner comment on construit des tableaux en dimensions supérieures à 2, il suffit d’utiliser un attribut shape plus élaboré :

shape = (2, 3, 4)
size = reduce(mul, shape)

# vous vous souvenez de arange
data = np.arange(size)
d3 = data.reshape(shape)
d3
array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]])

Cet exemple vous permet de voir qu’en dimensions supérieures la forme est toujours :

n1 x n2 x ... x lignes x colonnes

Enfin, ce que je viens de dire est arbitraire, dans le sens où, bien entendu, vous pouvez décider d’interpréter les tableaux comme vous voulez.

Mais en termes au moins de l’impression par print, il est logique de voir que l’algorithme d’impression balaye le tableau de manière mécanique comme ceci :

for i in range(2):
    for j in range(3):
        for k in range(4):
            array[i][j][k]

Et c’est pourquoi vous obtenez la présentation suivante avec des tableaux de dimensions plus grandes :

# la même chose avec plus de dimensions
shape = (2, 3, 4, 5)
size = reduce(mul, shape) # le produit des 4 nombres dans shape
size
120
data = np.arange(size)

# ce tableau est visualisé
# à base de briques de base
# de 4 lignes et 5 colonnes
d4 = data.reshape(shape)
d4
array([[[[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [ 10, 11, 12, 13, 14], [ 15, 16, 17, 18, 19]], [[ 20, 21, 22, 23, 24], [ 25, 26, 27, 28, 29], [ 30, 31, 32, 33, 34], [ 35, 36, 37, 38, 39]], [[ 40, 41, 42, 43, 44], [ 45, 46, 47, 48, 49], [ 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]]]])

Vous voyez donc qu’avec la forme :

2, 3, 4, 5

cela vous donne l’impression que vous avez comme brique de base des tableaux qui ont :

4 lignes
5 colonnes

Et souvenez-vous que vous pouvez toujours insérer un 1 n’importe où dans la forme, puisque ça ne modifie pas la taille qui est le produit des dimensions :

d2.shape
(2, 3)
d2
array([[100, 12, 13], [ 21, 22, 23]])
d2.reshape(2, 1, 3)
array([[[100, 12, 13]], [[ 21, 22, 23]]])
d2.reshape(2, 3, 1)
array([[[100], [ 12], [ 13]], [[ 21], [ 22], [ 23]]])

Ou même :

d2.reshape((1, 2, 3))
array([[[100, 12, 13], [ 21, 22, 23]]])
d2.reshape((1, 1, 1, 1, 2, 3))
array([[[[[[100, 12, 13], [ 21, 22, 23]]]]]])

Résumé des attributs

Voici un résumé des attributs des tableaux numpy :

attributsignificationexemple
shapetuple des dimensions(3, 5, 7)
ndimnombre dimensions3
sizenombre d’éléments3 * 5 * 7
dtypetype de chaque élémentnp.float64
itemsizetaille en octets d’un élément8

Divers

Je vous signale enfin, à titre totalement anecdotique cette fois, l’existence de la méthode ravel qui vous permet d’aplatir n’importe quel tableau :

d2
array([[100, 12, 13], [ 21, 22, 23]])
d2.ravel()
array([100, 12, 13, 21, 22, 23])
# il y a d'ailleurs aussi flatten qui fait
# quelque chose de semblable
d2.flatten()
array([100, 12, 13, 21, 22, 23])