data = list(range(1_000_000))
doubled = []
for x in data:
doubled.append(x * 2)
print(doubled[:5])[0, 2, 4, 6, 8]
Le moteur de tableaux sous pandas et scikit-learn — remplacez les boucles Python par des calculs rapides et vectorisés.
Apprenez les tableaux NumPy depuis la base : créez des tableaux, comprenez le dtype et la shape, faites de l’arithmétique élément par élément (vectorisée), maîtrisez le broadcasting, et sélectionnez des données par slicing, masques booléens et indexation avancée — sans oublier les agrégations et le redimensionnement.
26 juin 2026
7 juillet 2026
dtype fixe, shape fixe. C’est cette uniformité qui le rend rapide et compact en mémoire, contrairement à une liste Python.a + b ou np.sqrt(a) sur des tableaux entiers et NumPy exécute la boucle en C. C’est le même calcul sans le for de Python, et souvent 50 à 100× plus rapide.matrix + row fonctionne tout simplement (quand les shapes sont compatibles).a[1:3]), le masquage booléen (a[a > 0]) et l’indexation avancée (a[[0, 2, 4]]) couvrent presque tout ce dont vous aurez besoin.a.sum(), a.mean(axis=0), a.std(axis=1) : axis est la dimension que vous réduisez, pas celle que vous conservez..copy() quand vous avez besoin d’indépendance.Presque tous les outils numériques de Python reposent sur NumPy. Les DataFrames pandas sont des tableaux en dessous ; scikit-learn reçoit et renvoie des tableaux ; matplotlib les trace. Apprendre NumPy n’est donc pas une quête annexe — c’est le socle sur lequel tout le reste est bâti.
Tout l’intérêt de NumPy tient en une idée : arrêter d’écrire des boucles sur des nombres. Une simple liste Python vous oblige à traiter les éléments un par un, dans du bytecode Python lent. Un tableau NumPy stocke ses nombres dans un bloc de mémoire compact, tous du même type, si bien que NumPy peut exécuter la boucle en C compilé et utiliser les instructions vectorielles de votre processeur. Vous écrivez a * 2 ; NumPy fait le travail — plus rapide, plus court et plus lisible.
Cette leçon construit ce socle : créer des tableaux, leur dtype et leur shape, l’arithmétique vectorisée, le broadcasting (la partie sur laquelle tout le monde trébuche), les trois façons d’indexer, les agrégations et le redimensionnement.
Chaque résultat sur cette page est réel — et vous pouvez l’exécuter vous-même sans rien installer : cliquez sur Try ▸ sous n’importe quel bloc pour l’exécuter en direct dans votre navigateur (Python démarre au premier Run, puis c’est instantané), ou modifiez la cellule Essayez en direct vers la fin et appuyez sur Run.
Voici le contraste qui motive tout le reste. Supposons que vous vouliez doubler chaque nombre d’une collection d’un million d’éléments. La façon « liste Python » est une boucle explicite :
[0, 2, 4, 6, 8]
Ça fonctionne, mais chaque multiplication et chaque .append() s’exécute dans l’interpréteur Python — un million d’allers-retours. La façon NumPy est une expression unique sur le tableau entier :
[0 2 4 6 8]
Même résultat, sans for. C’est la vectorisation : une opération écrite une seule fois, appliquée à chaque élément à la vitesse native. Vérifions que c’est bel et bien plus rapide :
import numpy as np
py_list = list(range(1_000_000))
np_arr = np.arange(1_000_000)
import timeit
loop_time = timeit.timeit(lambda: [x * 2 for x in py_list], number=5) / 5
vec_time = timeit.timeit(lambda: np_arr * 2, number=5) / 5
print(f"Python loop: {loop_time*1000:.1f} ms")
print(f"NumPy vectorized: {vec_time*1000:.1f} ms")
print(f"Speed-up: {loop_time/vec_time:.0f}x")Python loop: 41.9 ms
NumPy vectorized: 1.4 ms
Speed-up: 31x
La version vectorisée est radicalement plus rapide, et l’écart se creuse à mesure que les données grandissent. Ce gain de vitesse est la raison d’être de NumPy — et la raison pour laquelle vous n’écrirez presque plus jamais de boucle for numérique.
Vous créerez des tableaux de plusieurs façons. La plus directe est np.array() à partir d’une liste Python :
[1 2 3 4]
[[1 2 3]
[4 5 6]]
Pour les plages et les grilles, NumPy vous fournit des générateurs pour vous éviter de saisir les valeurs à la main. arange est comme range mais renvoie un tableau ; linspace vous donne un nombre fixe de points régulièrement espacés (parfait pour tracer) ; zeros, ones et full construisent des tableaux pré-remplis d’une shape donnée :
[0 2 4 6 8]
[0. 0.25 0.5 0.75 1. ]
[0. 0. 0.]
[[1. 1. 1.]
[1. 1. 1.]]
[[7 7]
[7 7]]
Pour des données aléatoires — simulations, jeux de test, mélanges — utilisez un générateur. Le graine (seed) rend la sortie reproductible (vous obtenez les mêmes nombres « aléatoires » à chaque exécution, ce qui est précisément ce que l’on veut dans une leçon ou un test) :
[0.77395605 0.43887844 0.85859792 0.69736803]
[2 1 4 6 5]
[-0.31624259 -0.01680116 -0.85304393 0.87939797]
Deux attributs décrivent n’importe quel tableau. Le dtype est l’unique type partagé par chaque élément (int64, float64, bool, …) — cette uniformité est exactement ce qui rend les tableaux rapides. La shape est un tuple donnant la taille le long de chaque dimension :
dtype: int64
shape: (2, 3)
ndim: 2
size: 6
Vous pouvez fixer le dtype au moment de créer un tableau, ou convertir avec .astype(). Observez ce qui arrive aux décimales lorsque vous forcez le type entier :
[1 2 3]
Cette troncature est une surprise classique — .astype(int) coupe la décimale, il n’arrondit pas. Utilisez np.round() d’abord si vous voulez arrondir.
L’arithmétique sur les tableaux est élément par élément : l’opérateur est appliqué à chaque paire d’éléments correspondants, sans aucune boucle de votre côté. Des tableaux de même shape se combinent position par position :
[11 22 33 44]
[ 10 40 90 160]
[10. 10. 10. 10.]
[ 100 400 900 1600]
Il en va de même pour les fonctions mathématiques de NumPy — np.sqrt, np.exp, np.log, np.sin agissent toutes sur chaque élément d’un coup :
[1. 2. 3. 4.]
[0. 1.38629436 2.19722458 2.77258872]
Les comparaisons sont elles aussi vectorisées, et elles renvoient un tableau booléen — un True/False par élément. Retenez bien ceci ; c’est le moteur derrière le masquage booléen plus bas :
Jusqu’ici les tableaux concordaient. Le broadcasting est la règle qui permet à NumPy de combiner des tableaux de shapes différentes en étirant automatiquement le plus petit — sans jamais copier les données. C’est la fonctionnalité qui rend NumPy si fluide, et celle qui mérite d’être comprise avec précision.
Le cas le plus simple est un scalaire et un tableau. Le scalaire est traité comme s’il était étiré jusqu’à chaque position :
[101 102 103 104]
[0.5 1. 1.5 2. ]
Le cas intéressant est une ligne ajoutée à une matrice. Voici un exemple détaillé sur les shapes. Nous avons une matrice (3, 4) et une ligne de longueur 4, et nous voulons soustraire cette ligne de chaque ligne de la matrice — pensez à « soustraire les moyennes de colonnes de chaque ligne » :
[[ 9 18 27 36]
[10 19 28 37]
[11 20 29 38]]
Pourquoi cela fonctionne-t-il ? NumPy aligne les shapes en partant de la droite et les compare dimension par dimension. Deux dimensions sont compatibles si elles sont égales ou si l’une d’elles vaut 1 (ou est absente). Ici :
matrix: (3, 4)
row: (4,) → treated as (1, 4)
-----
result: (3, 4) → the length-1 first dim is stretched to 3
La première dimension absente de la ligne est traitée comme 1, puis étirée à 3 — si bien que la même ligne est soustraite des trois lignes de la matrice. Pas de boucle, pas de copie. Si les dimensions de fin ne concordent pas (et qu’aucune ne vaut 1), vous obtenez une ValueError — c’est l’erreur de discordance de shape que vous rencontrerez dans la section suivante.
Pour diffuser une colonne à la place, donnez-lui la shape (3, 1) afin qu’elle s’étire sur les colonnes :
Extraire des données d’un tableau commence de la même façon qu’avec une liste Python. Pour le 1D, indexez à partir de 0 (les négatifs comptent depuis la fin) et découpez avec start:stop:step (stop exclu) :
10
50
[20 30 40]
[10 30 50]
Pour le 2D, utilisez un indice par dimension à l’intérieur des crochets : arr[row, col]. Un : signifie « toute cette dimension », c’est ainsi que l’on récupère une ligne ou une colonne entière :
3
[4 5 6]
[1 4 7]
[[2 3]
[5 6]]
C’est celui que vous utiliserez constamment. Une comparaison vous donne un tableau booléen (de la section sur l’arithmétique) ; renvoyez ce masque dans les crochets et vous obtenez uniquement les éléments où il vaut True :
[False True True False True True]
[90 72 88 61]
[90 72 88 61]
Vous pouvez aussi affecter à travers un masque — une façon propre de plafonner ou de remplacer des valeurs sur place. Ici nous ramenons à 0 chaque score en échec :
[ 0 90 72 0 88 61]
Combinez les conditions avec & (et) et | (ou) — avec des parenthèses autour de chacune, car les opérateurs de NumPy ont une priorité élevée :
Passez une liste d’indices pour extraire exactement ces éléments, dans exactement cet ordre — répétitions comprises :
Réduire un tableau à un résumé — somme, moyenne, écart-type, min, max — est un appel de méthode. Sur le tableau entier vous obtenez un seul nombre :
21
3.5
1.707825127659933
La partie utile est axis. La règle qui garde tout le monde sur les rails : axis est la dimension que vous réduisez, pas celle que vous conservez. Pour un tableau 2D, axis=0 réduit les lignes (vous obtenez donc un résultat par colonne), et axis=1 réduit les colonnes (un résultat par ligne) :
[5 7 9]
[ 6 15]
[2.5 3.5 4.5]
Si vous oubliez lequel est lequel, rappelez-vous la shape de la réponse : axis=0 sur un tableau (2, 3) laisse la shape (3,) — le nombre de colonnes survit.
Les mêmes données peuvent revêtir différentes shapes. .reshape() réorganise les éléments en de nouvelles dimensions tant que le nombre total concorde ; -1 signifie « déduis cette dimension pour moi » :
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[ 0 1 2 3 4 5]
[ 6 7 8 9 10 11]]
Deux autres que vous emploierez : .ravel() aplatit n’importe quel tableau en 1D, et .T transpose (échange les lignes et les colonnes) :
Pour voir la vectorisation payer visuellement, construisez un axe x avec linspace, appliquez np.sin à tout le tableau d’un coup, et tracez le résultat. Pas de boucle — un tableau en entrée, un tableau en sortie :
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 4 * np.pi, 200) # 200 evenly spaced points
y = np.sin(x) # np.sin applied to the whole array
fig, ax = plt.subplots(figsize=(7, 3))
ax.plot(x, y, color="#3a86d4", linewidth=2)
ax.set_title("y = sin(x), computed on a NumPy array")
ax.set_xlabel("x")
ax.set_ylabel("sin(x)")
ax.grid(alpha=0.3)
plt.tight_layout()
plt.show()
Chaque point de cette courbe est issu d’un seul appel vectorisé — np.sin(x) — et non d’une boucle Python sur 200 angles.
Collez votre boucle for Python lente sur des nombres et demandez à Prova « vectorise ceci avec NumPy » — elle réécrit la boucle en une expression de tableau unique. Comme le runtime est juste là, vous exécutez les deux versions et vérifiez qu’elles concordent avec np.allclose(loop_result, vec_result), de sorte que vous faites confiance à la réécriture au lieu d’accepter une réponse plausible sur parole. The runtime is the judge. Demander à Prova →
Les blocs ci-dessus ont été exécutés au moment de la génération. Modifiez celui-ci et appuyez sur Run pour essayer NumPy par vous-même — il s’exécute dans votre navigateur via Pyodide (sans installation). Ou cliquez sur Try ▸ sous n’importe quel bloc ci-dessus pour y déposer son code.
Discordance de shape dans le broadcasting. Combiner des tableaux dont les dimensions de fin ne s’alignent pas (et ne valent pas 1) lève ValueError: operands could not be broadcast together. La solution est de vérifier .shape des deux côtés et de redimensionner pour que les dimensions soient égales ou que l’une vaille 1 :
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[26], line 5 3 a = np.array([1, 2, 3]) # shape (3,) 4 b = np.array([1, 2, 3, 4]) # shape (4,) ----> 5 a + b # 3 vs 4 — not compatible ValueError: operands could not be broadcast together with shapes (3,) (4,)
Surprises de dtype entier contre flottant. Un tableau d’entiers reste entier, si bien que la division entière tronque vers le bas et que vous ne pouvez pas y stocker de décimale. Si vous affectez 3.7 dans un tableau int, il est tronqué à 3. Créez le tableau en float (np.array([1, 2, 3], dtype=float)) lorsque vous y conserverez des décimales.
[9 2 3]
Une slice est une vue, pas une copie. Le slicing renvoie une fenêtre sur la même mémoire — modifier la slice modifie le tableau d’origine. Utilisez .copy() quand vous avez besoin d’un morceau indépendant :
original: [ 1 99 3 4 5]
with copy: [1 2 3 4 5]
array == array renvoie un tableau, pas un seul True/False. Comparer deux tableaux vous donne un tableau booléen élément par élément, il ne peut donc pas être utilisé directement dans un if. Réduisez-le avec .all() (« tous les éléments égaux ») ou .any() (« au moins un »), ou utilisez np.array_equal(a, b) pour comparer des tableaux entiers :
Une liste Python stocke des objets encapsulés dispersés en mémoire, et une boucle for les traite un par un à travers l’interpréteur. Un tableau NumPy stocke des nombres bruts d’un seul type dans un unique bloc contigu, si bien que NumPy peut exécuter toute l’opération en C compilé et utiliser les instructions vectorielles (SIMD) de votre processeur. Vous évitez entièrement le surcoût de l’interpréteur par élément, ce qui explique pourquoi le code vectorisé est couramment 50 à 100× plus rapide sur de grands tableaux.
Le broadcasting est la règle de NumPy pour faire de l’arithmétique entre des tableaux de shapes différentes sans copier les données. NumPy aligne les shapes en partant de la droite et, pour chaque dimension, les accepte si elles sont égales ou si l’une d’elles vaut 1 — la dimension de taille 1 (ou absente) est « étirée » pour correspondre. C’est ainsi que array + scalar, ou matrix + row, fonctionne tout simplement. Si les dimensions de fin ne concordent pas et qu’aucune ne vaut 1, vous obtenez une ValueError de broadcasting.
Utilisez un masque booléen. Écrivez la condition sur le tableau — a > 0 — qui renvoie un tableau booléen, puis indexez avec : a[a > 0] renvoie uniquement les éléments où la condition vaut True. Combinez les conditions avec & (et) et | (ou), en entourant chacune de parenthèses : a[(a > 0) & (a < 10)]. Vous pouvez aussi affecter à travers un masque, par ex. a[a < 0] = 0 pour plafonner les négatifs.
axis=0 et axis=1 ?
axis est la dimension que vous réduisez, pas celle que vous conservez. Pour un tableau 2D, axis=0 réduit le long des lignes et renvoie une valeur par colonne (par colonne), tandis que axis=1 réduit à travers les colonnes et renvoie une valeur par ligne (par ligne). Si vous oubliez, vérifiez la shape du résultat : axis=0 sur un tableau (2, 3) donne la shape (3,), donc les colonnes ont survécu.
Une liste est un conteneur souple et ordonné qui peut mélanger les types et grandir, mais elle est lente pour le calcul car chaque élément est un objet Python distinct. Un tableau NumPy est une grille de taille fixe d’un seul dtype, stockée de façon compacte, ce qui rend le calcul élément par élément, le broadcasting et les agrégations rapides et concis. Utilisez une liste pour la gestion générale ; utilisez un tableau dès l’instant où vous faites du travail numérique.
Travaillez chaque tâche dans la cellule Essayez en direct ci-dessus — modifiez et exécutez.
Tâche 1. Créez le tableau temps = np.array([18, 22, 30, 15, 27, 33]) (températures en °C). Sans boucle, produisez un nouveau tableau ne contenant que les températures au-dessus de 25.
Une comparaison comme temps > 25 crée un masque booléen ; indexez le tableau avec ce masque.
Tâche 2. Vous avez une matrice (2, 3) m = np.array([[1, 2, 3], [4, 5, 6]]). Calculez la moyenne de chaque colonne, puis la moyenne de chaque ligne.
axis est la dimension que vous réduisez. Les moyennes de colonnes réduisent les lignes ; les moyennes de lignes réduisent les colonnes.
Vérification rapide. Vous avez une matrice de shape (4, 3) et vous lui ajoutez un tableau 1D de shape (3,). Est-ce que ça fonctionne, et que calcule-t-il ?
Oui, ça fonctionne par broadcasting. NumPy aligne les shapes en partant de la droite : (4, 3) et (3,) — les dimensions de fin valent toutes deux 3, et la première dimension absente de la ligne est traitée comme 1 et étirée à 4. Le résultat est de shape (4, 3) : le même tableau de longueur 3 est ajouté à chacune des quatre lignes. (Si le tableau 1D avait eu la shape (4,) à la place, il ne se diffuserait pas — discordance de fin 3 contre 4 — et lèverait une ValueError.)
Les tableaux NumPy sont le socle numérique sous pandas, scikit-learn et matplotlib — et la raison pour laquelle Python est assez rapide pour le travail sur les données. L’habitude centrale est simple : stockez vos nombres dans un tableau, puis opérez sur le tableau entier d’un coup avec des calculs vectorisés, du broadcasting et des masques au lieu d’écrire des boucles. Familiarisez-vous avec dtype, shape, les trois façons d’indexer et l’argument axis, et vous aurez tout ce qu’il faut pour lire et écrire du vrai code numérique.
À lire aussi : DataFrames pandas — pandas s’appuie sur NumPy en ajoutant des étiquettes à ces tableaux · Vecteurs et types en R — R est vectorisé lui aussi, la même idée dans un autre langage.
@online{2026,
author = {},
title = {Tableaux NumPy en Python : calcul vectorisé, broadcasting et
indexation},
date = {2026-06-26},
url = {https://www.datanovia.com/learn/programming/python-foundations/numpy-arrays},
langid = {fr}
}