NumPy : calcul vectorisé

ndarray, vectorisation et broadcasting : la brique de calcul sous-jacente à l'écosystème data Python.

Créé le 19 août 2026·Mis à jour le 19 août 2026

Introduction


Une liste Python classique est une structure généraliste : elle peut contenir n'importe quel type d'objet, mélangés, et chaque élément est en réalité un pointeur vers un objet Python à part entière quelque part en mémoire. Cette flexibilité a un coût : parcourir une liste de 10 millions de nombres pour les additionner deux à deux implique 10 millions d'allers-retours dans l'interpréteur Python, chacun avec sa propre vérification de type.

NumPy (Numerical Python) résout ce problème en proposant une structure de tableau typée et contiguë en mémoire, sur laquelle les opérations s'exécutent en code C compilé plutôt qu'en boucle Python interprétée. C'est la fondation numérique de tout l'écosystème data en Python : pandas, scikit-learn, TensorFrow et PyTorch reposent tous, directement ou indirectement, sur les tableaux NumPy.

💡 Bon à savoir : c'est un peu le même raisonnement qui pousse à déléguer un calcul d'agrégation à une requête SQL plutôt qu'à une boucle PHP sur les résultats. On confie le travail lourd à une couche optimisée plutôt qu'à l'interpréteur du langage hôte.

Installation


pip install numpy

Convention universelle d'import, à respecter systématiquement :

import numpy as np

Le ndarray


La structure centrale de NumPy est le ndarray (N-dimensional array), un tableau à N dimensions dont tous les éléments partagent le même type.

Création de tableaux


import numpy as np

# Depuis une liste Python
a = np.array([1, 2, 3, 4, 5])

# Tableau à deux dimensions (matrice)
b = np.array([[1, 2, 3], [4, 5, 6]])

# Tableaux préremplis
zeros = np.zeros((3, 4))        # matrice 3x4 de zéros
ones = np.ones((2, 2))          # matrice 2x2 de uns
identite = np.eye(3)            # matrice identité 3x3

# Séquences
sequence = np.arange(0, 10, 2)  # [0, 2, 4, 6, 8]
lineaire = np.linspace(0, 1, 5) # 5 valeurs régulières entre 0 et 1

Propriétés essentielles


Chaque ndarray expose des propriétés qui décrivent sa structure :

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

a.shape    # (2, 3) : 2 lignes, 3 colonnes
a.ndim     # 2 : nombre de dimensions
a.dtype    # dtype('int64') : type des éléments
a.size     # 6 : nombre total d'éléments

Le dtype (data type) est ce qui rend le tableau compact et rapide : contrairement à une liste Python où chaque élément est un objet avec ses propres métadonnées, tous les éléments d'un ndarray partagent le même type primitif (int64, float64, bool, etc.), stocké de façon contiguë en mémoire, comme un tableau en C.

# Forcer un type précis
entiers = np.array([1, 2, 3], dtype=np.int32)
flottants = np.array([1, 2, 3], dtype=np.float64)

Indexation et slicing


L'indexation ressemble à celle des listes Python, mais s'étend naturellement aux tableaux multidimensionnels.

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

a[0, 0]      # 1 : première ligne, première colonne
a[1, :]      # [4, 5, 6] : toute la deuxième ligne
a[:, 2]      # [3, 6, 9] : toute la troisième colonne
a[0:2, 0:2]  # sous-matrice 2x2 en haut à gauche

# Indexation booléenne : filtrer selon une condition
a[a > 5]     # [6, 7, 8, 9] : tous les éléments strictement supérieurs à 5

L'indexation booléenne est un des outils les plus utilisés en pratique : elle permet de filtrer un tableau sans écrire de boucle explicite.

💡 Bon à savoir : contrairement au slicing sur une liste Python, un slice NumPy retourne généralement une vue (view) sur le tableau d'origine, pas une copie. Modifier le résultat d'un slice modifie donc le tableau original. Pour obtenir une copie indépendante, il faut appeler explicitement .copy().

Opérations vectorisées vs boucles Python


Le cœur de la performance de NumPy tient à la vectorisation : appliquer une opération à un tableau entier en une seule instruction, sans boucle Python explicite.

import numpy as np

a = np.arange(1_000_000)

# Approche vectorisée (NumPy)
resultat = a * 2

# Approche équivalente en boucle Python pure
resultat_boucle = [x * 2 for x in a]

Ces deux approches produisent le même résultat, mais leur exécution est radicalement différente en interne :

ApprocheOù s'exécute la boucleOrdre de grandeur
Boucle Python (for, compréhension)Dans l'interpréteur Python, élément par élémentRéférence (1x)
Opération vectorisée NumPyDans du code C compilé, sur le tableau entier10x à 100x plus rapide

La différence vient du fait que la version vectorisée délègue toute la boucle à une implémentation C optimisée, alors que la version Python doit repasser par l'interpréteur (vérification de type, appel de méthode, gestion mémoire) à chaque itération.

# Comparaison, addition, et toutes les opérations arithmétiques
# se vectorisent naturellement
a = np.array([1, 2, 3, 4, 5])
b = np.array([10, 20, 30, 40, 50])

a + b        # [11, 22, 33, 44, 55]
a * b        # [10, 40, 90, 160, 250]
a > 3        # [False, False, False, True, True]
np.sqrt(a)   # racine carrée élément par élément

# Agrégations
a.sum()      # 15
a.mean()     # 3.0
a.max()      # 5
a.std()      # écart-type

Broadcasting


Le broadcasting est le mécanisme qui permet à NumPy d'appliquer une opération entre deux tableaux de formes différentes, en étendant virtuellement le plus petit pour qu'il corresponde au plus grand, sans dupliquer physiquement la donnée en mémoire.

a = np.array([[1, 2, 3], [4, 5, 6]])  # shape (2, 3)
b = np.array([10, 20, 30])            # shape (3,)

a + b
# [[11, 22, 33],
#  [14, 25, 36]]

Ici, b est appliqué à chaque ligne de a sans qu'il soit besoin de le répéter explicitement. La règle générale : deux dimensions sont compatibles si elles sont égales, ou si l'une des deux vaut 1.

# Cas d'usage courant : normaliser chaque colonne
donnees = np.array([[1, 100], [2, 200], [3, 300]])
moyenne = donnees.mean(axis=0)   # moyenne de chaque colonne, shape (2,)
normalise = donnees - moyenne    # broadcasting automatique

Le paramètre axis mérite d'être retenu : axis=0 agrège verticalement (résultat par colonne), axis=1 agrège horizontalement (résultat par ligne). C'est une source d'erreur fréquente au début.

Résumé


ConceptDescription
ndarrayTableau typé, contigu en mémoire, à N dimensions
shapeDimensions du tableau (lignes, colonnes, ...)
dtypeType unique partagé par tous les éléments
VectorisationAppliquer une opération à tout le tableau sans boucle Python explicite
BroadcastingÉtendre virtuellement un tableau pour l'aligner sur un autre de forme différente

NumPy n'est presque jamais utilisé seul en pratique : il sert de fondation à des bibliothèques de plus haut niveau. La plus utilisée au quotidien pour manipuler des données tabulaires est pandas, qui construit ses structures (Series, DataFrame) directement sur des tableaux NumPy en interne, tout en offrant une API pensée pour des données étiquetées (colonnes nommées, index).