Aller au contenu

NumPy Cheatsheet

Référence professionnelle - Calcul scientifique Python

Import conventionnel

import numpy as np
Convention universelle. Toutes les références ci-dessous supposent cet alias.

Création de tableaux

Depuis des données Python

a = np.array([1, 2, 3])
Tableau 1D depuis une liste.
a = np.array([[1, 2], [3, 4]], dtype=np.float64)
Tableau 2D avec type explicite.
a = np.asarray(existing_list)
Évite une copie si la source est déjà un tableau compatible.

Tableaux initialisés

np.zeros((3, 4))
Tableau 3x4 de zéros (float64 par défaut).
np.ones((2, 3), dtype=np.int32)
Tableau 2x3 de uns en entier 32 bits.
np.full((3, 3), 7.0)
Tableau rempli d'une valeur constante.
np.empty((100, 100))
Allocation sans initialisation. Plus rapide quand la valeur initiale importe peu.
np.eye(4)
Matrice identité 4x4.
np.diag([1, 2, 3])
Matrice diagonale depuis un vecteur. np.diag(A) extrait la diagonale d'une matrice.
Python
np.zeros_like(a)
np.ones_like(a)
np.empty_like(a)
Crée un tableau de même forme et dtype que a.

Séquences

np.arange(0, 10, 2)
Entiers de 0 à 8, pas 2. Analogue de range.
array([0, 2, 4, 6, 8])
np.linspace(0, 1, 50)
50 valeurs régulièrement espacées entre 0 et 1 inclus.
np.logspace(0, 3, 4)
4 valeurs espacées logarithmiquement entre 10^0 et 10^3.
array([1., 10., 100., 1000.])
np.geomspace(1, 1000, 4)
Progression géométrique entre les valeurs spécifiées.

Grilles

Python
x = np.linspace(-1, 1, 100)
y = np.linspace(-1, 1, 100)
X, Y = np.meshgrid(x, y)
Grille 2D pour tracer des surfaces ou évaluer des fonctions f(x, y).
Python
xi = np.mgrid[0:5, 0:5]
xi = np.ogrid[0:5, 0:5]
mgrid retourne des tableaux complets. ogrid retourne des tableaux ouverts (économie mémoire).

Attributs d'un tableau

a.shape
Dimensions sous forme de tuple.
a.ndim
Nombre d'axes.
a.size
Nombre total d'éléments.
a.dtype
Type des éléments : float64, int32, complex128, bool, etc.
a.itemsize
Taille en octets d'un élément.
a.nbytes
Taille totale en mémoire : a.size * a.itemsize.
a.strides
Pas en octets pour chaque axe. Clé pour comprendre la disposition mémoire.
a.flags
Indique si le tableau est C-contigu, F-contigu, propriétaire, inscriptible.
Python
a.T          # transposé
a.real       # partie réelle
a.imag       # partie imaginaire
a.flat       # itérateur sur les éléments
a.data       # buffer mémoire brut
Attributs accesseurs courants.

Conversion de type

a.astype(np.float32)
Retourne une copie avec le nouveau dtype. Ne modifie pas a.
a.astype(np.int64, copy=False)
Évite la copie si le dtype est déjà compatible.

Reshape et manipulation des dimensions

a.reshape(3, 4)
Retourne une vue de forme (3, 4) si possible, sinon une copie. Ne modifie pas a.
a.reshape(3, -1)
-1 : dimension inférée automatiquement.
a.flatten()
Retourne une copie 1D. Toujours une copie.
a.ravel()
Retourne une vue 1D si possible, sinon une copie. Préférer à flatten pour les performances.
Python
a.T
np.transpose(a)
np.transpose(a, axes=(2, 0, 1))
Transposition. Avec axes, permutation arbitraire des dimensions.
np.swapaxes(a, 0, 1)
Échange deux axes.
Python
np.squeeze(a)
np.squeeze(a, axis=0)
Supprime les dimensions de taille 1.
Python
np.expand_dims(a, axis=0)
a[np.newaxis, :]
a[:, np.newaxis]
Ajoute un axe. Indispensable pour aligner des formes en broadcasting.

Assemblage et découpage

np.concatenate([a, b], axis=0)
Concatène selon un axe existant.
np.stack([a, b], axis=0)
Crée un nouvel axe. Les tableaux doivent avoir la même forme.
Python
np.vstack([a, b])   # axis=0
np.hstack([a, b])   # axis=1
Raccourcis pour l'empilement vertical et horizontal.
Python
np.split(a, 3, axis=0)
np.array_split(a, 5)
split exige des parties égales. array_split accepte des tailles inégales.

Indexing et slicing

Slicing de base

Python
a[2]         # élément
a[-1]        # dernier
a[1:4]       # indices 1, 2, 3
a[::2]       # un sur deux
a[::-1]      # ordre inverse
Slicing 1D standard. Retourne toujours une vue.
Python
A[0, 1]      # ligne 0, colonne 1
A[1:3, :]    # lignes 1 et 2, toutes colonnes
A[:, 2]      # colonne 2 (vecteur 1D)
A[:, 2:3]    # colonne 2 (matrice 2D)
Slicing multidimensionnel. A[:, 2] et A[:, 2:3] donnent des formes différentes.

Indexing booléen

Python
mask = a > 5
a[mask]           # éléments satisfaisant la condition
a[a % 2 == 0]     # éléments pairs
Retourne une copie. La forme du résultat est 1D.
Python
a[mask] = 0       # affectation conditionnelle
np.where(a > 5, a, 0)  # ternaire vectorisé
np.where avec trois arguments remplace le masque sans créer de copie intermédiaire.

Fancy indexing

Python
idx = [0, 2, 4]
a[idx]              # sélection par liste d'indices
A[[0, 1], [2, 3]]   # paires (0,2) et (1,3)
Retourne toujours une copie. Syntaxe différente du slicing.
Python
rows = np.array([0, 2])
cols = np.array([1, 3])
A[rows[:, np.newaxis], cols]
Sélection d'un sous-bloc non contigu via broadcasting d'indices.
Python
idx = np.nonzero(a > 5)
a[idx]
np.nonzero retourne les indices des éléments non nuls (ou vérifiant une condition via np.where(cond)).

Broadcasting

Règles

Python
# Alignement des formes depuis la droite.
# Une dimension vaut 1 : elle est étendue.
# Les dimensions incompatibles lèvent ValueError.

# Exemple : (3, 4) + (4,)  -> (3, 4)  OK
# Exemple : (3, 4) + (3,)  -> erreur
# Exemple : (3, 1) + (1, 4) -> (3, 4) OK
Comparaison dimension par dimension de droite à gauche. Une dimension manquante est traitée comme 1.

Exemples courants

Python
a = np.ones((3, 4))
b = np.array([1, 2, 3, 4])   # (4,)
a + b   # -> (3, 4)
Addition ligne par ligne.
Python
col = np.array([[1], [2], [3]])  # (3, 1)
row = np.array([10, 20, 30, 40]) # (4,)
col + row   # -> (3, 4)
Produit extérieur-like.
Python
X = np.random.default_rng().random((100, 5))
mean = X.mean(axis=0)   # (5,)
X_centered = X - mean   # (100, 5) - (5,)
Centrage d'un jeu de données par colonne.
Python
d = np.linalg.norm(
    X[:, np.newaxis] - X[np.newaxis, :],
    axis=-1
)
Matrice de distances euclidiennes (N, N) sans boucle.

Pièges courants

Python
a = np.arange(6).reshape(2, 3)
b = np.arange(2)  # (2,) != (3,)
a + b             # ValueError
L'alignement se fait par la droite : (2, 3) et (2,) sont incompatibles car 3 != 2.
Python
# Corriger avec newaxis
b = b[:, np.newaxis]  # (2, 1)
a + b                 # (2, 3) OK
Forcer la dimension pour l'axe correct.

Opérations vectorisées

Arithmétique élémentaire

Python
a + b,  a - b
a * b,  a / b
a // b, a % b
a ** b
-a
Opérateurs Python standard, appliqués élément par élément.
Python
np.add(a, b)
np.subtract(a, b)
np.multiply(a, b)
np.divide(a, b)
np.power(a, b)
Ufuncs équivalentes. Acceptent un paramètre out pour éviter une allocation.

Trigonométrie

Python
np.sin(a)
np.cos(a)
np.tan(a)
np.arcsin(a)
np.arctan2(y, x)
Toutes les fonctions trig classiques. arctan2 gère le quadrant.
Python
np.degrees(a)   # rad -> deg
np.radians(a)   # deg -> rad
np.pi           # constante pi
Conversions angulaires.

Exponentielles et logarithmes

Python
np.exp(a)
np.exp2(a)    # 2**a
np.expm1(a)   # exp(a) - 1, précis pour a proche de 0
Fonctions exponentielles.
Python
np.log(a)     # log naturel
np.log2(a)
np.log10(a)
np.log1p(a)   # log(1 + a), précis pour a proche de 0
Fonctions logarithmiques.

Arrondi et valeurs spéciales

Python
np.round(a, decimals=2)
np.floor(a)
np.ceil(a)
np.trunc(a)
Arrondi classique, plancher, plafond, troncature.
Python
np.abs(a)
np.sign(a)
np.clip(a, a_min, a_max)
np.sqrt(a)
np.cbrt(a)
Valeur absolue, signe, clipping, racines carrée et cubique.
Python
np.isnan(a)
np.isinf(a)
np.isfinite(a)
np.nan_to_num(a, nan=0.0)
Détection et traitement des valeurs spéciales IEEE 754.
Python
np.maximum(a, b)   # max élément par élément
np.minimum(a, b)
np.fmax(a, b)      # ignore les NaN
Maximum et minimum élément par élément entre deux tableaux.

Statistiques

Réductions

Python
a.sum()
a.sum(axis=0)    # somme par colonne
a.sum(axis=1)    # somme par ligne
a.sum(axis=0, keepdims=True)
keepdims=True conserve la dimension réduite pour le broadcasting.
Python
a.mean()
a.mean(axis=0)
np.nanmean(a)     # ignore les NaN
Moyenne arithmétique.
Python
np.median(a)
np.median(a, axis=0)
Médiane. Pas de méthode .median() sur ndarray, utiliser np.median.
Python
a.std()           # écart-type
a.var()           # variance
a.std(ddof=1)     # correction de Bessel (échantillon)
Par défaut, division par N (population). ddof=1 divise par N-1.
Python
a.min()
a.max()
a.min(axis=0)
np.nanmin(a)
np.nanmax(a)
Extremums globaux ou par axe.
Python
np.percentile(a, [25, 50, 75])
np.quantile(a, [0.25, 0.75], axis=0)
percentile prend des valeurs entre 0 et 100. quantile prend des valeurs entre 0 et 1.

Cumul et comptage

Python
np.cumsum(a)
np.cumsum(a, axis=0)
np.cumprod(a)
Sommes et produits cumulatifs.
Python
np.diff(a)
np.diff(a, n=2)    # différences d'ordre 2
np.gradient(a)
Différences consécutives. gradient utilise des différences centrées.
Python
np.histogram(a, bins=10)
np.histogram2d(x, y, bins=20)
np.digitize(a, bins)
Histogrammes et assignation de bacs.
Python
np.corrcoef(x, y)   # matrice de corrélation
np.cov(X.T)         # matrice de covariance
Corrélation et covariance. X.T : variables en lignes.

Tri et recherche

Python
np.sort(a)
np.sort(a, axis=0)
a.sort()           # en place
np.sort retourne une copie. a.sort() modifie a.
Python
np.argsort(a)
np.argsort(a, axis=0)
a[np.argsort(a)]   # équivaut à np.sort(a)
Retourne les indices qui trieraient le tableau.
Python
np.unique(a)
np.unique(a, return_counts=True)
np.unique(a, return_inverse=True)
Valeurs uniques triées. return_counts : occurrences. return_inverse : indices de reconstruction.
Python
np.where(a > 5)        # indices des vrais
np.where(a > 5, a, 0)  # remplacement conditionnel
Deux modes distincts selon le nombre d'arguments.
Python
a.argmax()
a.argmax(axis=0)
a.argmin()
np.argmax(a, axis=1)
Indice du maximum ou minimum le long d'un axe.
Python
np.searchsorted(sorted_a, v)
np.searchsorted(sorted_a, v, side='right')
Recherche binaire dans un tableau trié.
Python
np.partition(a, k)
np.argpartition(a, k)
Les k plus petits éléments garantis avant la k-ième position. Plus rapide que le tri complet.
Python
np.count_nonzero(a)
np.count_nonzero(a > 5)
Compte les éléments non nuls ou vérifiant une condition.

Algèbre linéaire

Produits

Python
A @ B              # produit matriciel
np.dot(A, B)       # équivalent
np.matmul(A, B)    # idem, pas de scalaire
@ est l'opérateur recommandé depuis Python 3.5. A * B est le produit élément par élément.
Python
np.inner(a, b)     # produit interne (vecteurs)
np.outer(a, b)     # produit extérieur
np.cross(a, b)     # produit vectoriel 3D
np.tensordot(A, B, axes=1)
Produits vectoriels et tensoriels.
Python
np.einsum('ij,jk->ik', A, B)   # @
np.einsum('ii->i', A)           # diagonale
np.einsum('ij->i', A)           # somme lignes
np.einsum('i,j->ij', a, b)      # produit externe
Notation Einstein. Exprime tout contraction/produit en une ligne.

Décompositions et résolution

np.linalg.solve(A, b)
Résout Ax = b. Préférer à inv(A) @ b (plus stable et plus rapide).
np.linalg.inv(A)
Inverse. Coûteux : éviter si possible. Utiliser solve.
np.linalg.det(A)
Déterminant.
Python
vals, vecs = np.linalg.eig(A)
vals, vecs = np.linalg.eigh(A)  # A symétrique
eigh est plus rapide et garantit des valeurs propres réelles pour les matrices symétriques.
Python
U, s, Vh = np.linalg.svd(A)
U, s, Vh = np.linalg.svd(A, full_matrices=False)
Décomposition en valeurs singulières. full_matrices=False : forme réduite (économique).
np.linalg.qr(A)
Décomposition QR.
np.linalg.cholesky(A)
Factorisation de Cholesky pour matrices définies positives.
x, res, rank, sv = np.linalg.lstsq(A, b, rcond=None)
Moindres carrés. Résout les systèmes surdéterminés.

Normes et rang

Python
np.linalg.norm(a)          # norme L2
np.linalg.norm(a, ord=1)   # norme L1
np.linalg.norm(A, ord='fro') # norme de Frobenius
Normes vectorielles et matricielles.
Python
np.linalg.matrix_rank(A)
np.linalg.cond(A)     # nombre de condition
np.trace(A)           # trace (somme diagonale)
Informations structurelles d'une matrice.

Génération aléatoire moderne

Initialisation

Python
rng = np.random.default_rng()
rng = np.random.default_rng(seed=42)
Crée un générateur reproductible. L'état est local à l'objet rng.
Python
rng1 = np.random.default_rng(42)
rng2 = np.random.default_rng(42)
# rng1 et rng2 produisent les mêmes séquences
Reproductibilité garantie par la graine.

Distributions

rng.random((3, 4)) # U[0, 1)
Distribution uniforme continue.
rng.uniform(low=0, high=10, size=(3, 4))
Uniforme sur [low, high).
rng.normal(loc=0, scale=1, size=(100,))
Distribution normale.
Python
rng.integers(0, 10, size=(5, 5))
rng.integers(0, 10, size=(5, 5), endpoint=True)
Entiers dans [low, high). Avec endpoint=True : [low, high].
Python
rng.exponential(scale=1.0, size=100)
rng.poisson(lam=3.0, size=100)
rng.binomial(n=10, p=0.5, size=100)
rng.beta(a=2, b=5, size=100)
Distributions statistiques courantes.
rng.standard_normal(size=(3, 3))
N(0, 1). Légèrement plus rapide que normal(0, 1, ...).

Échantillonnage et permutations

Python
rng.choice(a, size=5)
rng.choice(a, size=5, replace=False)  # sans remise
rng.choice(a, size=5, p=[0.1, 0.2, ...])
Tirage dans un tableau ou une population.
Python
rng.shuffle(a)           # en place
b = rng.permutation(a)   # copie mélangée
shuffle modifie a. permutation retourne une nouvelle copie.

Vues et copies

Python
b = a.view()       # même données, autre objet
b = a.copy()       # copie indépendante
b = a[:]           # VUE, pas une copie
b = a[[0, 1, 2]]   # copie (fancy indexing)
b = a[1:3]         # vue (slicing)
La distinction vue/copie est critique pour les performances et les effets de bord.
Python
b = a.view()
b.base is a        # True : b partage les données de a
b.flags.owndata    # False : b ne possède pas ses données

c = a.copy()
c.base is None     # True : c est indépendant
Vérifier si un tableau est une vue via .base et .flags.owndata.
Python
a = np.arange(12).reshape(3, 4)
b = a[:, ::2]      # vue des colonnes paires
b[0, 0] = 99       # modifie aussi a
Modifier une vue modifie le tableau source.
Python
a = np.arange(12)
b = a.reshape(3, 4)   # vue si possible
b = np.ascontiguousarray(a.T)  # force une copie C-contiguë
reshape retourne une vue tant que la disposition mémoire le permet.

Concepts avancés

Strides et disposition mémoire

Python
a = np.arange(12, dtype=np.float64).reshape(3, 4)
a.strides   # (32, 8) : 32 octets pour changer de ligne, 8 pour changer de colonne
Les strides définissent comment NumPy navigue en mémoire. Comprendre les strides permet de prédire les performances d'accès.
Python
a = np.array([[1, 2], [3, 4]], order='C')   # C-contigu (row-major)
b = np.array([[1, 2], [3, 4]], order='F')   # F-contigu (col-major, Fortran)

a.flags['C_CONTIGUOUS']   # True
b.flags['F_CONTIGUOUS']   # True
C-contigu : lignes consécutives en mémoire. F-contigu : colonnes consécutives. Impacte les performances des algos par ligne vs par colonne.
Python
a = np.lib.stride_tricks.as_strided(
    x,
    shape=(n - k + 1, k),
    strides=(x.strides[0], x.strides[0])
)
Manipulation directe des strides. Permet de créer des fenêtres glissantes sans copie. Utiliser avec précaution : pas de vérification de bornes.

Ufuncs

Python
np.add(a, b, out=c)         # sortie dans c
np.multiply(a, b, where=mask)  # conditionnel
np.add.reduce(a)            # équivaut à sum
np.add.accumulate(a)        # équivaut à cumsum
np.add.outer(a, b)          # produit extérieur
Les ufuncs exposent des méthodes de réduction et d'accumulation. out évite une allocation intermédiaire.
Python
f = np.frompyfunc(lambda x: x**2 + 1, 1, 1)
f(a)  # ufunc à partir d'une fonction Python
Transforme une fonction scalaire en ufunc. Utile mais plus lent que les ufuncs natives (pas de compilation).

einsum

Python
# Produit matriciel
np.einsum('ij,jk->ik', A, B)

# Trace d'une matrice
np.einsum('ii->', A)

# Produit scalaire
np.einsum('i,i->', a, b)

# Transposition
np.einsum('ij->ji', A)

# Somme sur un axe
np.einsum('ij->i', A)   # somme par ligne

# Produit externe
np.einsum('i,j->ij', a, b)

# Contraction de tenseur (batch matmul)
np.einsum('bij,bjk->bik', A, B)
La notation Einstein exprime n'importe quelle contraction. Les indices répétés à gauche et absents à droite sont contractés (sommés).

Réduction selon les axes

Python
A = np.random.default_rng(0).random((4, 3, 2))

A.sum(axis=0)   # -> (3, 2)
A.sum(axis=1)   # -> (4, 2)
A.sum(axis=2)   # -> (4, 3)
A.sum(axis=(0, 2))  # -> (3,)
Réduction multi-axes. L'axe réduit disparaît du résultat sauf avec keepdims=True.
Python
A.sum(axis=0, keepdims=True)  # -> (1, 3, 2)
# Permet le broadcasting direct
A / A.sum(axis=0, keepdims=True)
keepdims=True préserve la forme pour les opérations suivantes.

Vectorisation

Python
vf = np.vectorize(scalar_func)
vf(a)  # applique scalar_func élément par élément
np.vectorize est un wrapper pratique. N'apporte pas de performance : boucle interne en Python. Utiliser uniquement quand les ufuncs natives ne suffisent pas.
Python
# Lent
result = np.array([f(x) for x in a])

# Rapide : écrire f en opérations NumPy
result = np.sqrt(a**2 + 1)
La vraie vectorisation consiste à exprimer les calculs avec des opérations NumPy, pas à boucler sur les éléments.

Performances

Allocations et mémoire

Python
out = np.empty_like(a)
np.add(a, b, out=out)   # pas d'allocation
Le paramètre out des ufuncs évite une allocation intermédiaire dans les boucles critiques.
Python
np.ascontiguousarray(a)
np.asfortranarray(a)
Forcer la contiguïté améliore les performances des algos qui accèdent à la mémoire séquentiellement.
Python
a = np.float32(a)   # moitié de la mémoire vs float64
a = a.astype(np.float32)
float32 divise l'empreinte mémoire par deux. Acceptable pour la plupart des applications ML.

Pièges courants

Python
# Piège : copie inutile en concaténation itérative
for row in data:
    result = np.concatenate([result, row])  # O(n^2)

# Correct : accumuler en liste, convertir une fois
rows = []
for row in data:
    rows.append(row)
result = np.array(rows)  # O(n)
Les concaténations itératives ont un coût quadratique. Construire la liste Python en entier puis convertir.
Python
A * B    # produit élément par élément
A @ B    # produit matriciel
# Ne pas confondre
* n'est jamais un produit matriciel. C'est une source fréquente d'erreur silencieuse.
Python
a[:, 0]        # shape: (n,)   vecteur 1D
a[:, 0:1]      # shape: (n, 1) matrice colonne
a[:, [0]]      # shape: (n, 1) copie
# Les trois ont des comportements différents en broadcasting
La distinction entre (n,) et (n, 1) impacte le broadcasting. Utiliser reshape ou np.newaxis pour lever l'ambiguïté.
Python
view = a[1:3]    # vue
copy = a[[1, 3]] # copie (fancy)
view[0] = 99     # modifie a
copy[0] = 99     # ne modifie pas a
Slicing simple : vue. Fancy indexing : copie. Comportements opposés lors d'une affectation.

Cas pratiques

Normalisation et centrage

Python
X = rng.random((100, 5))

# Centrage-réduction (standardisation)
mean = X.mean(axis=0)
std  = X.std(axis=0)
X_std = (X - mean) / std
Standardisation colonne par colonne via broadcasting.
Python
# Normalisation min-max vers [0, 1]
xmin = X.min(axis=0)
xmax = X.max(axis=0)
X_norm = (X - xmin) / (xmax - xmin)
Chaque colonne mise à l'échelle indépendamment.
Python
# Normalisation L2 par ligne
norms = np.linalg.norm(X, axis=1, keepdims=True)
X_unit = X / norms
Chaque ligne devient un vecteur unitaire.

Distances

Python
a = np.array([1.0, 2.0, 3.0])
b = np.array([4.0, 5.0, 6.0])

# Distance euclidienne entre deux vecteurs
np.linalg.norm(a - b)

# Matrice de distances euclidiennes (N x N) sans boucle
X = rng.random((50, 3))
diff = X[:, np.newaxis] - X[np.newaxis, :]   # (50, 50, 3)
D = np.linalg.norm(diff, axis=-1)             # (50, 50)
Matrice de distances complète en deux lignes via broadcasting.

Filtrage et statistiques conditionnelles

Python
data = rng.normal(0, 1, size=10000)

# Valeurs au-delà de 2 écarts-types
outliers = data[np.abs(data) > 2]
print(f"{len(outliers)} valeurs aberrantes")
Détection de valeurs aberrantes par seuillage.
Python
A = rng.random((100, 5))

# Statistiques par colonne
col_means = A.mean(axis=0)    # (5,)
col_stds  = A.std(axis=0)     # (5,)

# Statistiques par ligne
row_sums  = A.sum(axis=1)     # (100,)
Réductions selon les axes pour des statistiques agrégées.
Python
labels = rng.integers(0, 3, size=100)
data   = rng.random((100, 4))

# Moyenne par groupe
for k in range(3):
    group_mean = data[labels == k].mean(axis=0)
Statistiques conditionnelles par groupe via masque booléen.

Algèbre linéaire appliquée

Python
# Régression linéaire via moindres carrés
A = np.column_stack([X, np.ones(len(X))])
coeffs, _, _, _ = np.linalg.lstsq(A, y, rcond=None)
Régression OLS sans bibliothèque externe.
Python
# ACP : décomposition en composantes principales
X_c = X - X.mean(axis=0)
U, s, Vh = np.linalg.svd(X_c, full_matrices=False)
# Composantes principales : Vh.T
# Coordonnées projetées : U * s
ACP via SVD sur la matrice centrée.

Signaux et transformées

Python
t = np.linspace(0, 1, 1000, endpoint=False)
signal = np.sin(2 * np.pi * 50 * t)
F = np.fft.fft(signal)
freqs = np.fft.fftfreq(len(t), d=t[1] - t[0])
FFT d'un signal 1D avec calcul des fréquences associées.
Python
np.fft.ifft(F)           # FFT inverse
np.fft.fft2(image)       # FFT 2D
np.fft.rfft(signal)      # FFT sur signal réel (moitié du spectre)
Variantes de la FFT selon le contexte.

Erreurs fréquentes

Python
# Erreur
A * B           # produit élément par élément
# Attendu
A @ B           # produit matriciel
Produit matriciel : * n'est jamais @. L'erreur est silencieuse si les formes sont compatibles par broadcasting.
Python
# Erreur : b est une vue de a
b = a[:]
b[0] = 99       # modifie aussi a

# Correct
b = a.copy()
b[0] = 99       # a est inchangé
Vue involontaire : le slicing retourne une vue. Utiliser .copy() pour une copie indépendante.
Python
# Formes ambiguës
a = np.array([1, 2, 3])      # shape: (3,)
b = np.array([[1, 2, 3]])    # shape: (1, 3)
c = np.array([[1], [2], [3]])# shape: (3, 1)

a @ b.T   # erreur
a.reshape(1, -1) @ b.T   # (1, 1) correct
Vecteur 1D vs matrice : (n,) et (1, n) ont un comportement différent en produit matriciel et en broadcasting.
Python
# Erreur : dtype entier coupe les décimales
a = np.array([1, 2, 3])    # int64
a / 2                       # -> array([0.5, 1. , 1.5])  OK en Python 3
a // 2                      # -> array([0, 1, 1])  division entière

# Attention à la troncature silencieuse
a = np.array([1, 2, 3], dtype=np.int32)
a[0] = 2.9    # stocke 2, pas 2.9
Troncature de type : affecter un float dans un tableau int tronque silencieusement.
Python
# Erreur : concaténation quadratique
result = np.array([])
for x in data:
    result = np.append(result, x)   # O(n^2)

# Correct
result = np.array(list(data))
np.append en boucle : chaque appel crée une copie. Accumuler dans une liste Python, puis convertir une seule fois.
Python
# Erreur : comparaison de flottants par ==
a = np.array([0.1 + 0.2])
a == 0.3   # -> array([False])  !

# Correct
np.isclose(a, 0.3)          # tolérance relative
np.allclose(a, 0.3)         # tous les éléments
Égalité flottante : ne jamais comparer des flottants avec ==. Utiliser np.isclose ou np.allclose.
Python
# Erreur : seed globale non reproductible en multiprocessing
np.random.seed(42)

# Correct : générateur local
rng = np.random.default_rng(42)
État global du random : l'état global n'est pas thread-safe. Utiliser un générateur local par thread ou processus.