← Retour au portfolio RSS

· 4 min de lecture

NumPy : penser en tableaux

Étape 1 de ma feuille de route IA : vectorisation, formes, broadcasting et algèbre linéaire, la base de tout l'écosystème.

Tout l’écosystème scientifique de Python repose sur NumPy : pandas stocke ses colonnes dans des tableaux NumPy, scikit-learn attend des tableaux NumPy, et les tenseurs de Keras en sont les cousins directs. Avant tout modèle, il faut donc apprendre à penser en tableaux plutôt qu’en boucles.

Pourquoi pas de simples listes Python ?

Une liste Python contient des objets quelconques, éparpillés en mémoire. Un tableau NumPy (ndarray) contient des valeurs d’un seul type, rangées côte à côte. Résultat : les opérations tournent en C, sur des blocs mémoire contigus, souvent 50 à 100 fois plus vite qu’une boucle Python.

import numpy as np

prix = np.array([12.5, 8.0, 23.9, 4.2])
tva = prix * 0.18        # une opération, appliquée à tout le tableau
print(tva)               # [2.25  1.44  4.302 0.756]

Pas de boucle : c’est la vectorisation, le réflexe numéro un à acquérir.

Forme, dimensions, type

Trois attributs à toujours avoir en tête :

x = np.zeros((3, 4))     # 3 lignes, 4 colonnes
x.shape                  # (3, 4)
x.ndim                   # 2
x.dtype                  # float64

En machine learning, la convention est presque toujours la même : une ligne = un exemple, une colonne = une caractéristique. Un jeu de 1 000 maisons décrites par 5 variables est un tableau de forme (1000, 5).

Pour changer de forme sans copier les données :

v = np.arange(12)        # [0, 1, ..., 11]
m = v.reshape(3, 4)      # 3 x 4
m.T.shape                # (4, 3) : la transposée

Indexation et masques

m[0]          # première ligne
m[:, 1]       # deuxième colonne
m[1:, :2]     # lignes 1 et 2, colonnes 0 et 1

notes = np.array([12, 7, 15, 9, 18])
notes[notes >= 10]          # [12 15 18] : filtrage par masque booléen
notes[notes < 10] = 10      # remplacement conditionnel, sans boucle

Les masques booléens reviennent partout : filtrer des données, compter des erreurs, sélectionner des classes.

Le broadcasting

NumPy sait combiner des tableaux de formes différentes quand c’est cohérent. Exemple classique : centrer chaque colonne d’un jeu de données.

X = np.random.default_rng(0).normal(size=(100, 3))
X_centre = X - X.mean(axis=0)   # (100, 3) - (3,) -> la moyenne est « diffusée »
X_centre.mean(axis=0).round(10) # [0. 0. 0.]

axis=0 agrège le long des lignes (un résultat par colonne), axis=1 le long des colonnes (un résultat par ligne). Se tromper d’axe est l’erreur la plus fréquente au début : vérifiez toujours la forme du résultat.

L’algèbre linéaire, là où tout se joue

Un modèle linéaire, c’est un produit matriciel. Avec X X de forme ( n , d ) (n, d) et des poids w w de forme ( d , ) (d,) :

y ^ = X w + b \hat{y} = Xw + b

rng = np.random.default_rng(42)
X = rng.normal(size=(200, 2))
w_vrai = np.array([3.0, -2.0])
y = X @ w_vrai + 1.0 + rng.normal(scale=0.1, size=200)

# Moindres carrés : on ajoute une colonne de 1 pour le biais
Xb = np.c_[X, np.ones(len(X))]
w, *_ = np.linalg.lstsq(Xb, y, rcond=None)
print(w.round(2))   # ≈ [ 3.  -2.   1. ]

C’est exactement la régression linéaire de mon article dédié, écrite en trois lignes.

Exercices pour valider l’étape

  1. Normaliser un tableau (n, d) pour que chaque colonne ait une moyenne 0 et un écart-type 1, sans boucle.
  2. Calculer la matrice des distances euclidiennes entre tous les points d’un nuage (n, 2) avec le broadcasting.
  3. Réimplémenter la descente de gradient de la régression linéaire en NumPy pur.
  4. Charger une image en tableau (hauteur, largeur, 3) et la passer en niveaux de gris.

Quand ces quatre exercices se font sans chercher la syntaxe à chaque ligne, l’étape est validée.

Ressources