Contactez-nous

NumPy : calcul numérique

Découvrez NumPy, la bibliothèque fondamentale pour le calcul numérique en Python. Apprenez à manipuler des tableaux multidimensionnels (arrays), à effectuer des opérations mathématiques vectorisées, et à profiter de la performance de NumPy.

Qu'est-ce que NumPy ? Une bibliothèque pour le calcul numérique

NumPy (Numerical Python) est une bibliothèque Python open source qui fournit des structures de données et des fonctions pour le calcul numérique.

L'élément central de NumPy est le tableau multidimensionnel (appelé `ndarray`, pour "N-dimensional array"). Un tableau NumPy est une grille de valeurs, toutes du *même type*, indexée par un tuple d'entiers positifs.

NumPy offre :

  • Des tableaux multidimensionnels (`ndarray`) performants.
  • Des fonctions mathématiques de haut niveau pour opérer sur ces tableaux (fonctions vectorisées).
  • Des outils pour l'algèbre linéaire, la transformée de Fourier, la génération de nombres aléatoires, etc.
  • Des outils pour intégrer du code C/C++ et Fortran.

NumPy est la base de nombreuses autres bibliothèques Python pour la science des données, le machine learning, et le calcul scientifique (comme Pandas, SciPy, Scikit-learn, Matplotlib, etc.).

NumPy est généralement importé avec l'alias `np` :

import numpy as np

Pourquoi utiliser NumPy ? Performance et expressivité

Pourquoi utiliser NumPy au lieu des listes Python standard pour les calculs numériques ?

  • Performance : Les tableaux NumPy sont stockés de manière contiguë en mémoire, et les opérations sur les tableaux NumPy sont implémentées en C (et Fortran), ce qui les rend beaucoup plus rapides que les opérations équivalentes sur des listes Python (qui sont des structures de données plus générales et moins optimisées pour le calcul numérique).
  • Vectorisation : NumPy vous permet d'effectuer des opérations sur des tableaux entiers sans avoir à écrire de boucles explicites. C'est ce qu'on appelle la vectorisation. Le code vectorisé est plus concis, plus lisible, et plus rapide.
  • Fonctions mathématiques : NumPy fournit un grand nombre de fonctions mathématiques optimisées pour les tableaux (fonctions trigonométriques, exponentielles, logarithmiques, statistiques, etc.).
  • Interopérabilité : NumPy est compatible avec de nombreuses autres bibliothèques scientifiques Python.

Exemple (comparaison de la performance entre une liste Python et un tableau NumPy):

import numpy as np
import time

# Création d'une grande liste et d'un grand tableau NumPy
taille = 1000000
liste = list(range(taille))
tableau = np.arange(taille)

# Additionner 1 à chaque élément (avec une boucle, version liste)
debut = time.time()
liste2 = [x + 1 for x in liste]
fin = time.time()
print(f"Temps avec liste : {fin - debut:.4f} secondes")

# Additionner 1 à chaque élément (vectorisation, version NumPy)
debut = time.time()
tableau2 = tableau + 1
fin = time.time()
print(f"Temps avec NumPy : {fin - debut:.4f} secondes")

Vous constaterez que l'opération avec NumPy est beaucoup plus rapide que l'opération équivalente avec une liste Python. La différence de performance est d'autant plus grande que la taille des données augmente.

Créer des tableaux NumPy (ndarrays)

Il existe plusieurs façons de créer des tableaux NumPy :

  • A partir d'une liste (ou d'un tuple) Python : Utilisez la fonction `np.array()`.
  • En utilisant des fonctions de création de tableaux : `np.zeros()`, `np.ones()`, `np.empty()`, `np.arange()`, `np.linspace()`, etc.
  • En lisant des données à partir d'un fichier.
  • En utilisant des fonctions de génération de nombres aléatoires.

Exemples :

import numpy as np

# A partir d'une liste
liste = [1, 2, 3, 4, 5]
tableau1 = np.array(liste)
print(tableau1)  # Affiche [1 2 3 4 5] (notez l'absence de virgules)

# A partir d'une liste de listes (tableau 2D)
liste_de_listes = [[1, 2, 3], [4, 5, 6]]
tableau2d = np.array(liste_de_listes)
print(tableau2d)  # Affiche un tableau 2D (matrice)

# Créer un tableau de zéros
zeros = np.zeros((3, 4))  # Tableau 3x4 rempli de zéros
print(zeros)

# Créer un tableau de uns
uns = np.ones((2, 5))
print(uns) # Tableau 2x5 rempli de uns

# Créer une séquence de nombres
sequence = np.arange(10)  # [0 1 2 3 4 5 6 7 8 9]
sequence_pas = np.arange(0,10,2) #[0 2 4 6 8]

# Créer un tableau de valeurs espacées linéairement
lineaire = np.linspace(0, 1, 5)  # 5 valeurs entre 0 et 1 (inclus)
print(lineaire)

# Créer un tableau avec des valeurs aléatoires
aleatoire = np.random.rand(2, 3)  # Tableau 2x3 de valeurs aléatoires entre 0 et 1
print(aleatoire)

Attributs importants des tableaux NumPy

Les tableaux NumPy ont plusieurs attributs importants qui décrivent leurs caractéristiques :

  • `ndim` : Le nombre de dimensions du tableau (par exemple, 1 pour un vecteur, 2 pour une matrice, etc.).
  • `shape` : Un tuple qui indique la taille du tableau dans chaque dimension. Par exemple, un tableau de forme `(3, 4)` a 3 lignes et 4 colonnes.
  • `size` : Le nombre total d'éléments dans le tableau.
  • `dtype` : Le type de données des éléments du tableau (par exemple, `int64`, `float64`, `bool`, etc.).
  • `itemsize` : La taille en octets de chaque élément du tableau.
  • `nbytes` : La taille totale en octets du tableau (`size * itemsize`).

Exemple :

import numpy as np

tableau = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32)

print("Nombre de dimensions :", tableau.ndim)     # 2
print("Forme :", tableau.shape)        # (2, 3)
print("Nombre d'éléments :", tableau.size)       # 6
print("Type de données :", tableau.dtype)      # int32
print("Taille d'un élément :", tableau.itemsize, "octets")  # 4 (octets, car int32)
print("Taille totale :", tableau.nbytes, "octets")    # 24 (octets)

Il est important de connaître ces attributs pour comprendre la structure et la taille de vos tableaux NumPy.

Opérations vectorisées : la puissance de NumPy

L'un des principaux avantages de NumPy est la possibilité d'effectuer des opérations *vectorisées* sur les tableaux. Cela signifie que vous pouvez appliquer une opération à tous les éléments d'un tableau en une seule fois, sans avoir à écrire de boucle explicite.

Les opérations vectorisées sont beaucoup plus rapides que les boucles équivalentes en Python pur, car elles sont implémentées en C.

Exemple :

import numpy as np

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

# Additionner 1 à chaque élément (vectorisation)
resultat = tableau + 1
print(resultat)  # Affiche [2 3 4 5 6]

# Multiplier chaque élément par 2
resultat = tableau * 2
print(resultat) # [ 2  4  6  8 10]

# Elever chaque élément au carré
resultat = tableau ** 2
print(resultat) #[ 1  4  9 16 25]

# Additionner deux tableaux élément par élément
tableau2 = np.array([5, 4, 3, 2, 1])
resultat = tableau + tableau2
print(resultat) # [6 6 6 6 6]

Vous pouvez effectuer des opérations arithmétiques (`+`, `-`, `*`, `/`, `**`, etc.), des comparaisons (`==`, `!=`, `<`, `>`, etc.), des opérations logiques (`&`, `|`, `~`), et de nombreuses autres opérations de manière vectorisée.

Les fonctions mathématiques de NumPy (comme `np.sin`, `np.cos`, `np.exp`, `np.log`, `np.sqrt`, etc.) sont également vectorisées : elles s'appliquent à chaque élément du tableau.

Indexation et slicing

L'indexation et le slicing fonctionnent sur les tableaux Numpy de la même manière (mais en plus puissant) que sur les listes.

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

#Accéder à un élément
print(tableau[0])

#Slicing
print(tableau[1:4])

#Avec un pas
print(tableau[::2])

Pour les tableaux multidimensionnels, on utilise un tuple d'indices.

tableau_2d = np.array([[1, 2, 3], [4, 5, 6]])

print(tableau_2d[0, 1]) #Première ligne (index 0), deuxième colonne (index 1) : 2
print(tableau_2d[1, :]) #Deuxième ligne entière : [4, 5, 6]
print(tableau_2d[:, 2]) #Troisième colonne entière: [3, 6]