6.2. Le ndarray

Le ndarray est le type qui contient les données numériques dans numpy. Il est deux choses en une : un unique bloc de données compact et un petit descripteur placé devant ce bloc qui indique comment le lire.

6.2.1. À l’intérieur de la boîte

Le bloc de données contient chaque élément du tableau bout à bout, sans rien d’autre entre eux. Chaque élément occupe le même nombre d’octets – un pour un tableau de valeurs uint8, deux pour uint16, quatre pour float. Un tableau uint8 de 256 éléments fait exactement 256 octets de données ; les mêmes 256 nombres dans une list Python occupent un kilo-octet – un emplacement 32 bits par élément, quel que soit le faible nombre de bits dont la valeur a réellement besoin.

Le descripteur enregistre ce que le bloc signifie. Cinq valeurs suffisent à décrire n’importe quel tableau rectangulaire, quel que soit le nombre de dimensions :

  • dtype – le type d’élément. Détermine combien d’octets chaque élément occupe et quelle plage de valeurs il peut contenir (abordé dans Dtypes).

  • itemsize – la largeur en octets d’un élément, dérivée du dtype.

  • ndim – le nombre de dimensions (1 pour un vecteur, 2 pour une matrice, 3 pour un volume, jusqu’à 4).

  • shape – la taille le long de chaque dimension, sous forme de tuple.

  • strides – comment parcourir le bloc de données pour traverser chaque axe. Abordé dans Forme et pas (strides).

C’est tout. Chaque chemin rapide de numpy – arithmétique, réductions, diffusion (broadcasting), tranchage – fonctionne directement à partir de ces cinq valeurs plus le pointeur de données, sans surcoût Python par élément.

6.2.2. Ce que la conception apporte

Trois propriétés découlent de « bloc compact + petit descripteur » et définissent le comportement du reste de la section.

Les calculs par élément s’exécutent en un seul appel. a + b entre deux tableaux de forme correspondante additionne les deux tampons et en écrit un troisième, le tout à l’intérieur d’un unique appel de bibliothèque. np.sin(a) fait de même pour le sinus de chaque élément. Les opérateurs arithmétiques, de comparaison et bit-à-bit fonctionnent tous de cette manière.

Regarder les mêmes données sous un autre angle est gratuit. Demander une sous-région d’un tableau, ou les mêmes données disposées sous une forme différente, ne déplace aucun octet. L’opération renvoie un nouveau descripteur pointant vers le même bloc de données. Le résultat est appelé une vue – une seconde fenêtre sur le même tampon sous-jacent. Écrire à travers une vue écrit dans la source.

Les formes mixtes fonctionnent quand même. Un tableau plus court face à un plus long, une ligne face à une matrice, une colonne face à une ligne – numpy les aligne par diffusion (broadcasting), un petit ensemble de règles qui décident quel axe court s’étire pour correspondre au long. L’étirement est virtuel ; aucune donnée n’est dupliquée.

6.2.3. Ce que la conception coûte

Deux restrictions découlent de la même conception.

Chaque élément a le même type. Une liste peut contenir un int à côté d’un str à côté d’une liste de trois autres valeurs int ; un ndarray ne le peut pas. Le dtype est fixé au moment de la construction. La page Dtypes couvre le petit ensemble de types que numpy prend en charge et les règles qui découlent du fait d’en fixer un.

Agrandir un tableau n’est pas gratuit. Une liste conserve des emplacements libres à la fin et prend en charge .append à faible coût. Un ndarray a exactement la taille dont il a besoin ; y ajouter un élément signifierait allouer un nouveau tampon plus grand et y copier l’ancien contenu. Il n’y a pas de méthode append(), à dessein. Le bon motif sur la caméra est de préallouer la destination à sa taille finale et de la remplir ; Performances couvre la technique.

Avec un tampon typé et compact pour les données, un petit descripteur pour les métadonnées et trois garanties de comportement (calculs par élément rapides, vues alternatives des mêmes données sans copie, et formes qui se diffusent), le ndarray est la fondation sur laquelle repose le reste du chapitre. La façon dont un tableau voit réellement le jour – à partir d’un littéral, d’une allocation pré-remplie, d’un tampon de périphérique – est la prochaine question pratique.