Section courante

A propos

Section administrative du site

Tableaux et calcul vectorisé

La bibliothèque NumPy, tirant son nom de l'abréviation de l'anglicisme Numerical Python, est l'un des paquets fondamentaux les plus importants pour le calcul numérique en Python. La plupart des paquets de calcul fournissant des fonctionnalités scientifiques utilisent les objets de tableau de NumPy comme langue véhiculaire pour l'échange de données.

Voici quelques-unes des fonctionnalités que vous trouverez dans NumPy :

Étant donné que NumPy fournit une API en langage de programmation C facile à utiliser, il est simple de transmettre des données à des bibliothèques externes écrites dans un langage de programmation de bas niveau et également pour les bibliothèques externes de renvoyer des données à Python sous forme de tableaux NumPy. Cette fonctionnalité a fait de Python un langage de prode choix pour encapsuler les bases de code C/C++/Fortran héritées et leur donner une interface dynamique et facile à utiliser.

Bien que NumPy ne fournisse pas en soi de fonctionnalités de modélisation ou scientifiques, une compréhension des tableaux NumPy et du calcul orienté tableau vous aidera à utiliser les outils avec une sémantique orientée tableau, comme pandas, beaucoup plus efficacement.

Pour la plupart des applications d'analyse de données, les principaux domaines de fonctionnalité sont :

Bien que NumPy fournisse une base informatique pour le traitement général des données numériques, de nombreux lecteurs voudront utiliser pandas comme base pour la plupart des types de statistiques ou d'analyses, en particulier sur les données tabulaires. pandas fournit également des fonctionnalités plus spécifiques au domaine, comme la manipulation de séries chronologiques, n'étant pas présente dans NumPy.

Note : Le calcul orienté tableau dans Python remonte à 1995, lorsque Jim Hugunin a créé la bibliothèque Numeric. Au cours des 10 années suivantes, de nombreuses communautés de programmation scientifique ont commencé à faire de la programmation de tableaux en Python, mais l'écosystème de la bibliothèque s'est fragmenté au début des années 2000. En 2005, Travis Oliphant a pu forger le projet NumPy à partir des projets Numeric et Numarray de l'époque pour rassembler la communauté autour d'un seul cadre de calcul de tableau.

L'une des raisons pour lesquelles NumPy est si important pour les calculs numériques en Python est qu'il est conçu pour être efficace sur de grands tableaux de données. Il y a plusieurs raisons à cela :

Pour vous donner une idée de la différence de performances, considérez un tableau NumPy d'un million d'entiers et la liste Python équivalente :

  1. import numpy as np
  2. mon_tableau = np.arange(1000000)
  3. ma_liste = list(range(1000000))     

Multiplions maintenant chaque séquence par 2 :

  1. %time for _ in range(10): mon_tableau2 = mon_tableau * 2

Pour obtenir :

CPU times: user 20 ms, sys: 8 ms, total: 28 ms
Wall time: 26.5 ms

Ensuite :

  1. %time for _ in range(10): ma_liste2 = [x * 2 for x in ma_liste]

Pour obtenir :

CPU times: user 408 ms, sys: 64 ms, total: 472 ms
Wall time: 473 ms

Les algorithmes basés sur NumPy sont généralement 10 à 100 fois plus rapides (ou plus) que leurs homologues Python purs et utilisent beaucoup moins de mémoire.

Le ndarray de NumPy : un objet tableau multidimensionnel

L'une des fonctionnalités clefs de NumPy est son objet tableau N-dimensionnel, ou ndarray, étant un conteneur rapide et flexible pour les grands ensembles de données en Python. Les tableaux vous permettent d'effectuer des opérations mathématiques sur des blocs entiers de données en utilisant une syntaxe similaire aux opérations équivalentes entre éléments scalaires.

Pour vous donner une idée de la façon dont NumPy permet des calculs par lots avec une syntaxe similaire aux valeurs scalaires sur les objets Python intégrés, on importe d'abord NumPy et génère un petit tableau de données aléatoires :

  1. import numpy as np
  2.  
  3. # Générer des données aléatoires
  4. data = np.random.randn(2, 3)
  5. data

On obtiendra un résultat ressemblant à ceci :

array([[-0.01609597, -0.31927867,  0.58715762],
       [ 0.2821461 , -0.76816857, -1.55024241]])

On écrit ensuite des opérations mathématiques avec des données :

  1. data * 10

On obtiendra un résultat ressemblant à ceci :

array([[ -0.16095966,  -3.19278668,   5.87157616],
       [  2.82146104,  -7.68168565, -15.50242413]])

Si on écrit :

  1. data + data

On obtiendra un résultat ressemblant à ceci :

array([[-0.03219193, -0.63855734,  1.17431523],
       [ 0.56429221, -1.53633713, -3.10048483]])

Dans le premier exemple, tous les éléments ont été multipliés par 10. Dans le second, les valeurs correspondantes dans chaque «cellule» du tableau ont été additionnées les unes aux autres.

Note : L'espace de noms numpy est vaste et contient un certain nombre de fonctions dont les noms sont en conflit avec les fonctions Python intégrées (comme min et max).

Un ndarray est un conteneur multidimensionnel générique pour des données homogènes ; c'est-à-dire que tous les éléments doivent être du même type. Chaque tableau a une forme, un tuple indiquant la taille de chaque dimension et un dtype, un objet décrivant le type de données du tableau :

  1. data.shape

On obtiendra un résultat ressemblant à ceci :

(2, 3)

Si on écrit :

  1. data.dtype

On obtiendra un résultat ressemblant à ceci :

dtype('float64')

Créer des ndarrays

La façon la plus simple de créer un tableau est d'utiliser la fonction array. Elle accepte tout objet de type séquence (y compris d'autres tableaux) et produit un nouveau tableau NumPy contenant les données transmises. Par exemple, une liste est un bon candidat pour la conversion :

  1. data1 = [5, 7.5, 8, 0, 1]
  2. arr1 = np.array(data1)
  3. arr1

On obtiendra un résultat ressemblant à ceci :

array([5. , 7.5, 8. , 0. , 1. ])

Les séquences imbriquées, comme une liste de listes de longueur égale, seront converties en un tableau multidimensionnel :

  1. data2 = [[1, 2, 3, 4], [5, 6, 7, 8]]
  2. arr2 = np.array(data2)
  3. arr2

On obtiendra un résultat ressemblant à ceci :

array([[1, 2, 3, 4],
       [5, 6, 7, 8]])

Étant donné que data2 est une liste de listes, le tableau NumPy arr2 a deux dimensions avec une forme déduite des données. Nous pouvons le confirmer en inspectant les attributs ndim et shape :

  1. arr2.ndim

On obtiendra un résultat ressemblant à ceci :

2

Ensuite :

  1. arr2.shape

On obtiendra un résultat ressemblant à ceci :

(2, 4)

Sauf indication explicite (nous y reviendrons plus tard), np.array tente de déduire un bon type de données pour le tableau qu'il crée. Le type de données est entreposé dans un objet de métadonnées dtype spécial ; par exemple, dans les deux exemples précédents, nous avons :

  1. arr1.dtype 

On obtiendra un résultat ressemblant à ceci :

dtype('float64')

Ensuite :

  1. arr2.dtype

On obtiendra un résultat ressemblant à ceci :

dtype('int64')

En plus de np.array, il existe un certain nombre d'autres fonctions permettant de créer de nouveaux tableaux. Par exemple, les zéros et les uns créent des tableaux de 0 ou de 1, respectivement, avec une longueur ou une forme donnée. empty crée un tableau sans initialiser ses valeurs à une valeur particulière. Pour créer un tableau de dimension supérieure avec ces méthodes, transmettez un tuple pour la forme :

  1. np.zeros(10)

On obtiendra un résultat ressemblant à ceci :

array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])

Ensuite :

  1. np.zeros((3, 7))

On obtiendra un résultat ressemblant à ceci :

array([[0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0.]])

Ensuite :

  1. np.empty((2, 3, 2))

On obtiendra un résultat ressemblant à ceci :

array([[[0., 0.],
        [0., 0.],
        [0., 0.]],
       [[0., 0.],
        [0., 0.],
        [0., 0.]]])

Attention : Il n'est pas prudent de supposer que np.empty renverra un tableau contenant uniquement des zéros. Dans certains cas, il peut renvoyer des valeurs «poubelles» non initialisées.

arange est une version à valeur de tableau de la fonction de l'intervalle intégrée de Python :

  1. np.arange(16)

On obtiendra un résultat ressemblant à ceci :

array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15])

Consultez le tableau suivant pour obtenir une courte liste des fonctions de création de tableau standard. Étant donné que NumPy est axé sur le calcul numérique, le type de données, s'il n'est pas spécifié, sera dans de nombreux cas float64 (virgule flottante).

Fonction Description
array Convertir les données d'entrée (liste, tuple, tableau ou autre type de séquence) en un ndarray soit en déduisant un dtype, soit en spécifiant explicitement un dtype ; copie les données d'entrée par défaut.
asarray Convertir l'entrée en ndarray, mais ne pas copier si l'entrée est déjà un ndarray
arange Comme l'intervalle intégrée mais renvoie un ndarray au lieu d'une liste
ones, ones_like Produire un tableau de tous les 1 avec la forme et le type de données donnés ; ones_like prend un autre tableau et produit un tableau de uns de la même forme et du même type de données
zeros, zeros_like Comme ones et ones_like mais produisant des tableaux de 0 à la place
empty, empty_like Créez de nouveaux tableaux en allouant une nouvelle mémoire, mais ne les remplissez pas avec des valeurs telles que des uns et des zéros
full, full_like Produire un tableau de la forme et du type de données donnés avec toutes les valeurs définies sur la «valeur de remplissage» indiquée. full_like prend un autre tableau et produit un tableau rempli de la même forme et du même type de données.
eye, identity Créer une matrice identité carrée N × N (1 sur la diagonale et 0 ailleurs)

Types de données pour les ndarrays

Le type de données ou dtype est un objet spécial contenant les informations (ou métadonnées, données sur les données) dont le ndarray a besoin pour interpréter un bloc de mémoire comme un type particulier de données :

  1. arr1 = np.array([1, 2, 3], dtype=np.float64)
  2. arr2 = np.array([1, 2, 3], dtype=np.int32)
  3. arr1.dtype

On obtiendra un résultat ressemblant à ceci :

dtype('float64')

Ensuite :

  1. arr2.dtype

On obtiendra un résultat ressemblant à ceci :

dtype('int32')

Les dtypes sont une source de flexibilité pour NumPy pour interagir avec des données provenant d'autres systèmes. Dans la plupart des cas, ils fournissent une cartographie directement sur un disque sous-jacent ou une représentation en mémoire, ce qui facilite la lecture et l'écriture de flux binaires de données sur le disque et permet également de se connecter à du code écrit dans un langage de programmation de bas niveau comme C ou Fortran. Les dtypes numériques sont nommés de la même manière : un nom de type, comme float ou int, suivi d'un nombre indiquant le nombre de bits par élément. Une valeur à virgule flottante double précision standard (ce qui est utilisé sous le capot dans l'objet float de Python) occupe 8 octets ou 64 bits. Ainsi, ce type est connu dans NumPy sous le nom de float64. Voir le tableau suivant pour une liste complète des types de données pris en charge par NumPy :

Type Code de type Description
int8, uint8 i1, u1 Types d'entiers 8 bits (1 octet) signés et non signés
int16, uint16 i2, u2 Types d'entiers 16 bits signés et non signés
int32, uint32 i4, u4 Types d'entiers 32 bits signés et non signés
int64, uint64 i8, u8 Types d'entiers 64 bits signés et non signés
float16 f2 Virgule flottante demi-précision
float32 f4 ou f Virgule flottante simple précision standard ; compatible avec le float de C
float64 f8 ou d Virgule flottante double précision standard ; compatible avec le double de C et l'objet float de Python.
float128 f16 ou g Virgule flottante de précision étendue
complex64, complex128, complex256 c8, c16, c32 Nombres complexes représentés respectivement par deux nombres flottants 32, 64 ou 128
bool ? Type booléen entreposant les valeurs True et False
object O Type d'objet Python ; une valeur peut être n'importe quel objet Python
string_ S Type de chaîne ASCII de longueur fixe (1 octet par caractère) ; par exemple, pour créer un type de chaîne d'une longueur de 10, utilisez «S10»
unicode_ U Type Unicode de longueur fixe (nombre d'octets spécifique à la plateforme) ; même sémantique de spécification que string_ (par exemple, «U10»)

Remarque : Ne vous inquiétez pas de mémoriser les dtypes NumPy, surtout si vous êtes un nouvel utilisateur. Il est souvent nécessaire de se soucier uniquement du type général de données que vous traitez, qu'il s'agisse de données à virgule flottante, complexes, entières, booléennes, de chaînes ou d'objets Python généraux. Lorsque vous avez besoin de plus de contrôle sur la façon dont les données sont entreposées en mémoire et sur le disque, en particulier les grands ensembles de données, il est bon de savoir que vous avez le contrôle sur le type d'entreposage.

Vous pouvez convertir ou convertir explicitement un tableau d'un type de données à un autre en utilisant la méthode astype de ndarray :

  1. arr = np.array([1, 2, 3, 4, 5])
  2. arr.dtype

On obtiendra un résultat ressemblant à ceci :

dtype('int64')

Ensuite :

  1. float_arr = arr.astype(np.float64)
  2. float_arr.dtype

On obtiendra un résultat ressemblant à ceci :

dtype('float64')

Dans cet exemple, les entiers ont été convertis en nombres à virgule flottante. Si on convertit certains nombres à virgule flottante en nombres de type entier, la partie décimale sera tronquée :

  1. arr = np.array([3.8, -1.2, -2.7, 0.5, 12.7, 10.1])
  2. arr

On obtiendra un résultat ressemblant à ceci :

array([ 3.8, -1.2, -2.7, 0.5, 12.7, 10.1])

Ensuite :

  1. arr.astype(np.int32)

On obtiendra un résultat ressemblant à ceci :

array([ 3, -1, -2, 0, 12, 10], dtype=int32)

Si vous avez un tableau de chaînes de caractères représentant des nombres, vous pouvez utiliser astype pour les convertir sous forme numérique :

  1. numeric_strings = np.array(['1.25', '-9.7', '42'], dtype=np.string_)
  2. numeric_strings.astype(float)

On obtiendra un résultat ressemblant à ceci :

array([ 1.25, -9.7 , 42. ])

Attention : Il est important d'être prudent lors de l'utilisation du type numpy.string_, car les données de chaîne de caractères dans NumPy sont de taille fixe et peuvent tronquer l'entrée sans avertissement. pandas a un comportement prêt à l'emploi plus intuitif sur les données non numériques.

Si le moulage échoue pour une raison quelconque (comme une chaîne de caractères ne pouvant pas être convertie en float64), une ValueError sera générée. Ici, on aurait pu écrire float au lieu de np.float64 ; NumPy alias les types Python vers ses propres dtypes de données équivalents.

Vous pouvez également utiliser l'attribut dtype d'un autre tableau :

  1. int_array = np.arange(10)
  2. calibers = np.array([.22, .270, .358, .370, .44, .50], dtype=np.float64)
  3. int_array.astype(calibers.dtype)

On obtiendra un résultat ressemblant à ceci :

array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])

Il existe des chaînes de code de type abrégé que vous pouvez également utiliser pour faire référence à un dtype :

  1. empty_uint32 = np.empty(8, dtype='u4')
  2. empty_uint32

On obtiendra un résultat ressemblant à ceci :

array([1635017060,  540876849,  539768411,  741682743,  539768864,
        824192048,  168632413,    6029312], dtype=uint32)

Remarque : L'appel de astype crée toujours un nouveau tableau (une copie des données), même si le nouveau dtype est le même que l'ancien dtype.



Dernière mise à jour : Vendredi, le 20 septembre 2024