NumPy
Créer
import numpy as np
np.array([[1, 2], [3, 4]])
np.zeros((2, 3))
np.ones((2, 3), dtype=np.float32)
np.full((2, 2), 7)
np.eye(3)
np.arange(0, 10, 2) # 0 2 4 6 8, borne exclue
np.linspace(0, 1, 5) # 5 points, bornes incluses
rng = np.random.default_rng(42) # API moderne, préférée à np.random.seed
rng.normal(0, 1, size=(2, 3))
rng.integers(0, 10, size=5)
rng.choice([1, 2, 3], size=4, replace=True)
a = np.arange(6).reshape(2, 3)
print(a)
print(a.shape, a.dtype, a.ndim, a.size)
[[0 1 2]
[3 4 5]]
(2, 3) int64 2 6
Formes
a.reshape(3, 2)
a.reshape(-1) # aplatit, -1 = "déduis la dimension"
a.T # transposée
a[:, np.newaxis] # ajoute un axe -> (2, 1, 3)
np.squeeze(a) # retire les axes de taille 1
np.concatenate([a, a], axis=0)
np.stack([a, a]) # crée un nouvel axe
reshape renvoie une vue quand c'est possible : modifier le résultat modifie
l'original. .copy() pour couper le lien.
Indexer
a[0, 1]
a[:, 1] # toute la colonne 1
a[1:, :2]
a[a > 2] # masque booléen -> tableau 1D
a[[0, 1], [2, 0]] # fancy indexing -> éléments (0,2) et (1,0)
a = np.arange(6).reshape(2, 3)
print(a > 2)
print(a[a > 2])
[[False False False]
[ True True True]]
[3 4 5]
Le masque booléen est le pattern à avoir : np.where(cond, x, y) pour choisir élément par
élément, a[cond] = valeur pour affecter.
Agréger
a.sum() # tout
a.sum(axis=0) # somme des lignes -> un résultat par colonne
a.sum(axis=1) # un résultat par ligne
a.mean(), a.std(), a.min(), a.max()
a.argmax(), a.argmin() # position, pas valeur
np.median(a), np.percentile(a, 95)
Le sens d'axis est le piège classique : axis=0 fait disparaître l'axe 0, donc agrège
les lignes et laisse une valeur par colonne.
a = np.arange(6).reshape(2, 3)
print(a.sum(axis=0), a.sum(axis=1))
[3 5 7] [ 3 12]
Avec des NaN : np.nanmean, np.nansum, sinon tout devient NaN.
Broadcasting
a = np.ones((3, 4))
b = np.arange(4) # (4,)
a + b # (3, 4) : b est étiré sur les lignes
Règle : on aligne les shapes par la droite, et deux dimensions sont compatibles si elles sont égales ou si l'une vaut 1.
(3, 4) + (4,) -> (3, 4) ✅
(3, 4) + (3,) -> erreur ❌ (3 ≠ 4 sur le dernier axe)
(3, 4) + (3, 1) -> (3, 4) ✅
Pour corriger le cas d'erreur : a + b[:, np.newaxis].
Algèbre linéaire
A @ B # produit matriciel
A * B # produit terme à terme
np.dot(u, v) # produit scalaire
np.linalg.norm(v)
np.linalg.inv(A)
np.linalg.solve(A, b) # résout Ax = b, mieux que inv(A) @ b
np.linalg.eig(A)
Vectoriser au lieu de boucler
# lent
out = [x ** 2 + 1 for x in data]
# rapide
out = data ** 2 + 1
Une boucle Python sur un tableau NumPy annule tout l'intérêt de NumPy. Si la logique semble
imposer une boucle, chercher du côté de np.where, np.select, des masques, ou d'un
reshape + agrégation par axe.
Similarité cosinus, en pratique
def cosine(a: np.ndarray, b: np.ndarray) -> np.ndarray:
a = a / np.linalg.norm(a, axis=-1, keepdims=True)
b = b / np.linalg.norm(b, axis=-1, keepdims=True)
return a @ b.T
keepdims=True conserve la dimension pour que la division broadcaste correctement — sans
lui, la shape passe de (n, 1) à (n,) et la division échoue ou donne un résultat faux.
Sauvegarder
np.save("arr.npy", a)
a = np.load("arr.npy")
np.savez("plusieurs.npz", x=a, y=b)
np.savetxt("arr.csv", a, delimiter=",")