Maîtriser NumPy : Guide complet des opérations sur les tableaux multi-dimensionnels

NumPy (Numerical Python) constitue le socle de l'écosystème scientifique en Python. Cette bibliothèque fournit un objet tableau multidimensionnel performant, appelé ndarray, ainsi que des outils pour manipuler ces structures avec une efficacité largement supérieure aux listes natives de Python.

Initialisation et création de tableaux

La création de tableaux peut s'effectuer à partir de structures existantes ou via des fonctions dédiées pour générer des données spécifiques.

import numpy as np

# Création à partir de listes
liste_simple = [10, 20, 30]
vecteur = np.array(liste_simple)

# Tableau de zéros ou de uns avec un typage spécifique
zone_vide = np.zeros((3, 5), dtype=float)
matrice_unite = np.ones((2, 4), dtype=int)

# Génération de séquences numériques
sequence = np.arange(0, 20, 2)  # Début, fin, pas
points_equidistants = np.linspace(0, 1, 10)  # Début, fin, nombre d'éléments

# Matrices particulières
identite = np.eye(4)

Génération de données aléatoires

L'utilisation de l'interface moderne Generator est recommandée pour la reproductibilité et la performance.

generateur = np.random.default_rng(seed=12345)

# Entiers aléatoires dans un intervalle
valeurs_int = generateur.integers(0, 100, size=(3, 3))

# Distribution normale (moyenne=0, écart-type=1)
dist_normale = generateur.standard_normal((4, 2))

Inspection des propriétés structurelles

Chaque tableau NumPy possède des attributs qui décrivent sa morphologie et sa consommation mémoire.

data = generateur.integers(10, size=(2, 3, 5))

print(f"Nombre de dimensions : {data.ndim}")
print(f"Format du tableau : {data.shape}")
print(f"Nombre total d'éléments : {data.size}")
print(f"Type de données : {data.dtype}")
print(f"Taille d'un élément (octets) : {data.itemsize}")

Indexation et découpage (Slicing)

L'accès aux données dans NumPy suit une syntaxe proche de celle des listes Python, mais étendue aux dimensions multiples.

# Manipulation d'un vecteur 1D
v = np.arange(10)
sous_ensemble = v[2:8:2]  # start:stop:step
inverse = v[::-1]

# Accès multidimensionnel
matrice = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
element = matrice[1, 2]  # Ligne 1, Colonne 2 (valeur 6)

# Extraction de sous-matrices
bloc = matrice[:2, 1:]  # Deux premières lignes, colonnes à partir de l'index 1

Redimensionnement et transformation de forme

La modification de la structure d'un tableau est une opération fréquente, souvent réalisée sans copie de données en mémoire.

base = np.arange(12)
# Transformation en matrice 3x4
grille = base.reshape((3, 4))

# Transposition (échange lignes/colonnes)
grille_t = grille.T

# Aplatissement du tableau
vecteur_plat = grille.ravel()

Concaténation et séparation

Fusionner ou diviser des tableaux permet de manipuler des jeux de données complexes.

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

# Assemblage horizontal et vertical
h_fused = np.concatenate([a, b])
v_fused = np.vstack([a, b])

# Découpage d'un tableau
data_split = np.arange(16).reshape((4, 4))
haut, bas = np.vsplit(data_split, [2])

Calcul Vectorisé et Fonctions Universelles (ufuncs)

La force de NumPy réside dans sa capacité à appliquer des opérations sur des tableaux entiers sans boucles explicites en Python.

x = np.array([1, 2, 3])
y = np.array([4, 5, 6])

# Opérations arithmétiques élément par élément
somme = x + y
puissance = x ** 2

# Fonctions mathématiques intégrées
logarithme = np.log(x)
moyenne = np.mean(y)
ecart_type = np.std(y)
somme_totale = np.sum(x)

Le mécanisme de Diffusion (Broadcasting)

Le broadcasting permet d'effectuer des opérations entre des tableaux de dimensions différentes selon des règles strictes de compatibilité.

m = np.ones((3, 3))
v = np.array([0, 1, 2])

# Le vecteur v est "diffusé" sur chaque ligne de la matrice m
resultat = m + v

Optimisation de performance : Vectorisation vs Boucles

L'utilisation des fonctions natives de NumPy est cruciale pour le traitement de gros volumes de données.

import time

gros_volume = generateur.random(1_000_000)

# Approche lente (Boucle Python)
def inverse_loop(values):
    res = np.empty(len(values))
    for i in range(len(values)):
        res[i] = 1.0 / values[i]
    return res

start = time.time()
inverse_loop(gros_volume)
print(f"Temps boucle : {time.time() - start:.4f}s")

# Approche rapide (Vectorisation NumPy)
start = time.time()
resultat_opti = 1.0 / gros_volume
print(f"Temps vectorisé : {time.time() - start:.4f}s")

Gestion de la mémoire : Vues vs Copies

Le slicing dans NumPy crée par défaut une "vue" du tableau original. Modifier une vue impacte l'objet source.

original = np.array([1, 2, 3, 4])
vue = original[:2]
vue[0] = 99  # Modifie aussi 'original'

# Pour éviter cela, utiliser explicitement .copy()
copie_independante = original[:2].copy()
copie_independante[0] = -1  # 'original' reste inchangé

Filtrage et Masquage Booléen

Extraire des données basées sur des conditions logiques est une opération fondamentale en analyse de données.

observations = np.array([15, 22, 8, 19, 31, 12])

# Création d'un masque logique
masque = (observations > 10) & (observations < 25)

# Application du masque
selection = observations[masque]

# Remplacement conditionnel
nettoyage = np.where(observations < 10, 0, observations)

Étiquettes: NumPy python-data-science vectorization array-manipulation scientific-computing

Publié le 17 juin à 05h53