~/wiki

NumPy

Mis à jour le 2026-08-07Confiance : high
numpypythonarrayvectorisationalgebre-lineairebroadcasting

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=",")

See also