Traitement des données NumPy : un guide pratique
Le traitement des données NumPy consiste à charger, remodeler, nettoyer et réduire des tableaux numériques avec la bibliothèque NumPy, dont l’objet principal « ndarray » stocke des données homogènes dans un bloc de mémoire contigu de taille fixe. Depuis sa sortie en 2006, NumPy est devenu le substrat de SciPy, des pandas, de scikit-learn et de la plupart des Python scientifiques, de sorte que les habitudes que vous construisez ici se propagent partout.
Points clés à retenir
- Le
ndarrayest une vue à foulées sur une mémoire tampon plate ; comprendre les foulées explique pourquoi le « remodelage », le découpage et la « transposition » sont bon marché alors que la « copie » et l’indexation sophistiquée ne le sont pas. - La vectorisation n’est pas simplement stylistique : elle déplace la boucle du Python interprété vers le C compilé, et l’accélération est généralement d’un à deux ordres de grandeur pour les travaux arithmétiques lourds.
- La disposition de la mémoire (ordre
CvsF) et le choix du dtype importent souvent plus que le choix de l’algorithme pour les grands tableaux de simulation ; un tableau float64 de 10 ^ 8 éléments consomme déjà 800 Mo avant toute copie. - Pour les tableaux qui ne rentrent pas dans la RAM,
numpy.memmapet l’accès sauvegardé par HDF5 (h5py) vous permettent de traiter par morceaux sans réécrire votre code d’analyse pour le traitement des données numpy. - La reproductibilité dépend du contrôle explicite du RNG (
np.random.default_rng(seed)), de l’épinglage des versions et de l’enregistrement du type et de la forme avec les résultats.
Qu’est-ce que NumPy (et pourquoi c’est important pour le traitement)
L’abstraction centrale de NumPy est un tableau multidimensionnel typé avec une forme, un type et un ensemble de strides décrivant le nombre d’octets à ignorer pour atteindre l’élément suivant le long de chaque axe. Cette décision de conception – séparer la forme logique de la disposition physique – est ce qui rend NumPy à la fois rapide et flexible.
Un tableau float64 (1000, 1000) occupe 8 Mo de mémoire contiguë ; sa transposition ne déplace pas un seul octet, elle réécrit uniquement les métadonnées de strides. Le découpage se comporte de la même manière : a[::2] renvoie une vue, pas une copie.
L’implication pratique du traitement des données numpy est que vous devez savoir quand vous détenez une vue et quand vous en détenez une copie. Les vues sont bon marché et partagent la mémoire, donc en modifier une modifie l’original.
Les copies sont sûres mais doublent votre mémoire maximale. La propre documentation de NumPy sur les vues et copies de tableaux est la référence faisant autorité, et elle vaut la peine de la lire attentivement une fois plutôt que de déboguer un bug d’alias silencieux plus tard.
Les types méritent la même attention. La sortie de simulation arrive souvent par défaut sous la forme float64, mais une trajectoire de dynamique moléculaire de coordonnées atomiques nécessite rarement plus de float32 pour la visualisation, et les nombres entiers (indices d’atomes, numéros de trame) doivent être int32 ou int64 plutôt que float. Réduire de moitié le dtype réduit de moitié le trafic mémoire, ce qui constitue souvent le coût dominant pour les opérations liées à la bande passante mémoire.
Connexes : — Parcours de science des données basés sur des projets avec un terminal guidé et des ensembles de données réels.
Le flux de travail de traitement des données de base
Un pipeline de traitement de données NumPy typique pour le travail scientifique comporte cinq étapes : ingérer, inspecter, nettoyer, transformer et réduire. Chaque étape dispose d’outils NumPy idiomatiques, et sauter l’étape d’inspection est la source la plus courante d’erreurs en aval.
Ingestion. np.loadtxt et np.genfromtxt gèrent le texte brut mais sont lents pour les gros fichiers car ils analysent ligne par ligne en Python. np.load avec .npy/.npz est le chemin binaire rapide. Pour HDF5 – la norme de facto en matière de calcul haute performance, maintenue par le groupe HDF – utilisez h5py ou PyTables, qui exposent les ensembles de données sous forme d’objets de type tableau prenant en charge les lectures partielles.
Inspecter. Avant toute opération arithmétique, vérifiez arr.shape, arr.dtype et np.isnan(arr).any(). Un rapide arr.min(), arr.max() et arr.mean() révèle des erreurs d’unité et des valeurs sentinelles (une erreur courante est -9999 utilisée comme marqueur pour les données manquantes dans les ensembles de données environnementales). Cette vérification en trois lignes détecte plus de bogues que n’importe quelle suite de tests.
Ça vaut le coup d'oeil : — Un abonnement pour les certificats Python et de science des données soutenus par l'université.
Nettoyage. Les valeurs manquantes dans NumPy sont représentées par np.nan pour les flottants, et NaN se propage par l’arithmétique de par sa conception. Utilisez np.nanmean, np.nanstd et np.nansum pour les ignorer, ou np.isnan pour les masquer explicitement. Notez que les tableaux d’entiers ne peuvent pas contenir NaN – un piège courant lors de la lecture de données CSV contenant des blancs.
Transformation. Les opérations de remodelage, de diffusion et par axe sont en direct ici. arr.reshape(-1, 3) transforme un flux de coordonnées plat en triples xyz ; arr - arr.mean(axis=0) centre chaque colonne ; np.einsum exprime des contractions tensorielles qui nécessiteraient autrement des boucles imbriquées.
Réduire. Agrégation le long des axes avec sum, mean, std, argmin et percentile. Pour les réductions groupées, np.add.at ou np.bincount gèrent le cas où vous devez accumuler par index plutôt que par bloc contigu.
Vectorisation, diffusion et coût des boucles
La vectorisation signifie exprimer une opération sur des tableaux entiers afin que NumPy la répartisse vers des boucles compilées. L’exemple canonique : le calcul des distances par paires entre 10 000 points avec une double boucle Python prend de l’ordre de 10^8 itérations interprétées ; la forme avec broadcasting np.sqrt(((a[:, None, :] - b[None, :, :])**2).sum(-1)) fait le même travail en C, au prix de la matérialisation d’un grand tableau intermédiaire.
Les règles de diffusion sont le mécanisme qui rend cela concis pour le traitement des données numpy. NumPy aligne les formes à partir de la droite et étend les dimensions de taille 1.
Un tableau (N, 3) moins un tableau (3,) soustrait le vecteur de chaque ligne. Un tableau (N, 1) multiplié par un tableau (1, M) produit (N, M). Les règles sont documentées dans le guide de diffusion NumPy, et leur internalisation supprime la plupart des boucles « for » du code numérique.
Le compromis est la mémoire. La diffusion peut créer des temporaires beaucoup plus grands que les entrées. Lorsque cela devient un goulot d’étranglement, divisez le calcul ou utilisez « np.einsum » avec « optimize=True », ce qui supprime certains intermédiaires. Pour les problèmes véritablement liés aux boucles qui résistent à la vectorisation, le décorateur @njit de Numba compile les boucles Python en code machine et constitue souvent la trappe de sortie pragmatique.
Comparaison : Choisir le bon outil pour le travail
| Tâche | NumPy idiomatique | Quand chercher autre chose |
|---|---|---|
| Charger une trajectoire de 50 Go | np.memmap ou h5py lecture fragmentée | Dask ou Zarr pour un accès parallèle/cloud |
| Agrégation groupe par | np.bincount, np.add.at | pandas groupby pour les données étiquetées de type mixte |
| Distances par paires | Diffusion + einsum | SciPy cdist/pdist (mémoire optimisée) |
| Matrices clairsemées | np.zeros (dense) | SciPy « clairsemé » — la densité gaspille plus de 90 % de mémoire |
| Mathématiques élémentaires personnalisées | Fonctions vectorisées | Numba ou Cython quand la logique est branchée |
| Échantillonnage reproductible | np.random.default_rng(seed) | — (c’est la bonne API moderne) |
Le modèle de traitement des données numpy : NumPy est la bonne représentation par défaut, mais les tableaux denses sont une mauvaise représentation pour les données clairsemées ou étiquetées, et les tableaux sur une seule machine sont la mauvaise représentation pour les données hors noyau.
Mémoire, Dtypes et traitement hors cœur
La mémoire est généralement la contrainte contraignante dans le travail scientifique NumPy et le traitement des données numpy, et non le processeur. Trois techniques répondent à cette question.
Tout d’abord, choisissez délibérément les types. np.float32 réduit de moitié la mémoire par rapport à float64 et est souvent suffisant pour des résultats intermédiaires ; np.int8 ou np.uint16 couvrent la plupart des tableaux d’index et d’étiquettes. NumPy effectuera une conversion ascendante silencieusement lors d’opérations mixtes, alors vérifiez avec arr.dtype après l’arithmétique.
Deuxièmement, utilisez des tableaux mappés en mémoire. np.memmap mappe un fichier sur le disque dans l’espace d’adressage, vous permettant de découper un tableau de 100 Go comme s’il était dans la RAM, le système d’exploitation chargeant uniquement les blocs nécessaires. Cela fonctionne bien pour les modèles d’accès séquentiels et mal pour l’accès aléatoire sur l’ensemble du tableau.
Troisièmement, traitez en morceaux. La lecture d’un ensemble de données HDF5 en blocs de, disons, 10 000 lignes et l’accumulation d’une moyenne courante ou d’un histogramme limitent la mémoire maximale, quelle que soit la taille du fichier. Il s’agit du modèle standard dans les pipelines bioinformatiques qui diffusent des lectures de séquençage et dans les flux de travail climatiques qui réduisent la production de modèles multidécennaux.
Une subtilité : arr.copy() et l’indexation sophistiquée (arr[idx_array]) allouent toutes deux. En boucle serrée sur des morceaux, ces allocations dominent le temps d’exécution. La réutilisation d’un tampon de sortie pré-alloué avec np.copyto ou l’argument out= à ufuncs évite le churn.
Reproductibilité et provenance
Le travail numérique reproductible dans le traitement des données numpy nécessite le contrôle de trois éléments que NumPy touche directement : le caractère aléatoire, le type et la version.
Caractère aléatoire : l’état global hérité np.random.seed est déconseillé. L’API moderne est rng = np.random.default_rng(seed), qui renvoie un Générateur isolé dont l’état ne fuit pas entre les fonctions. Ceci est important lorsque les travailleurs parallèles ont chacun besoin de flux indépendants et reproductibles.
Dtype : enregistrez le type de chaque tableau que vous conservez. Un résultat calculé dans float32 et un résultat calculé dans float64 diffèrent par les derniers chiffres, et les réviseurs comparant les résultats doivent savoir lequel a été utilisé. L’enregistrement avec np.save préserve le type ; l’enregistrement au format CSV ne fait pas cela.
Version : le comportement de NumPy a changé au fil des versions d’une manière qui affecte les résultats - par exemple, le type entier par défaut sous Windows et la gestion de certaines réductions. Épingler NumPy dans votre fichier d’environnement et enregistrer la version dans les métadonnées de sortie est une pratique courante dans les outils de recherche reproductibles. Les notes de version NumPy documentent ces modifications.
Pour la provenance, stockez la forme, le type et un hachage de l’entrée à côté des résultats. Des outils comme « numpy.testing.assert_allclose » avec une tolérance explicite rendent les tests de régression significatifs plutôt que fragiles.
Intégration de NumPy à la pile plus large
NumPy est rarement seul dans le traitement des données numpy. pandas enveloppe les tableaux NumPy avec des axes étiquetés et constitue le bon outil lorsque vos données comportent des colonnes hétérogènes ou des étiquettes de lignes significatives ; la conversion avec .to_numpy() est sans copie lorsque les types s’alignent. SciPy s’appuie sur NumPy pour l’algèbre linéaire, l’optimisation et le traitement du signal — « scipy.linalg » est généralement préféré à « numpy.linalg » pour tout ce qui va au-delà des résolutions de base. scikit-learn consomme et renvoie les tableaux NumPy partout. Matplotlib les trace directement.
Le contrat d’interopérabilité est l’interface du tableau, formalisée sous le nom de standard API Python Array, qui permet à des bibliothèques comme CuPy, JAX et PyTorch d’exposer des API compatibles NumPy. L’écriture du code d’analyse sur ce sous-ensemble le rend portable sur les GPU avec un minimum de modifications – un réel avantage lorsqu’une simulation dépasse la taille d’un poste de travail.
Une mise en garde : les conversions implicites entre ces bibliothèques copient les données. Déplacer un tableau NumPy vers un GPU avec les transferts « cupy.asarray » de CuPy via PCIe ; conserver les données résidentes sur un seul appareil et regrouper les transferts est beaucoup plus rapide que l’aller-retour par opération.
Sources et lectures complémentaires
- Traitement des données — Wikipédia : Le traitement des données est la collecte et la manipulation de données numériques pour produire des informations significatives. Le traitement des données est une forme de traitement de l’information qui…
Questions fréquemment posées
Qu’est-ce que le traitement des données NumPy ?
Le traitement des données NumPy implique l’utilisation du « ndarray » de la bibliothèque NumPy pour charger, nettoyer, transformer et réduire les données numériques. Il couvre la lecture de tableaux à partir de fichiers, la gestion des valeurs manquantes avec des fonctions compatibles NaN, le remodelage et la diffusion, ainsi que l’agrégation le long des axes. Étant donné que la plupart des bibliothèques scientifiques Python s’appuient sur NumPy, il s’agit de la couche fondamentale des pipelines numériques.
NumPy est-il plus rapide que les pandas pour le traitement des données ?
NumPy est plus rapide pour les tableaux numériques homogènes car il fonctionne directement sur la mémoire contiguë sans surcharge d’index ou de répartition de types. pandas est plus rapide à écrire et mieux adapté aux données tabulaires étiquetées de type mixte. Pour les calculs numériques volumineux, la conversion d’un DataFrame pandas en un tableau NumPy avec .to_numpy() et le traitement là-bas constituent une optimisation courante.
Comment gérer les données manquantes dans NumPy ?
Les tableaux à virgule flottante représentent les valeurs manquantes sous la forme « np.nan », et NumPy fournit « np.nanmean », « np.nanstd », « np.nansum » et « np.isnan » pour travailler avec eux. Les tableaux d’entiers ne peuvent pas stocker NaN, donc convertissez-les en flottant ou utilisez une valeur sentinelle plus un masque booléen. Les tableaux masqués via np.ma offrent une alternative plus structurée.
NumPy peut-il traiter des données plus volumineuses que la RAM ?
Oui, en utilisant « np.memmap » pour mapper un fichier disque dans l’espace d’adressage, ou en lisant les ensembles de données HDF5 en morceaux avec h5py. Les deux approches limitent la mémoire maximale. Pour le traitement parallèle ou distribué sur plusieurs machines, Dask et Zarr étendent le même modèle de tableau au-delà d’un seul nœud.
Quelle est la différence entre une vue et une copie dans NumPy ?
Une vue partage la mémoire tampon du tableau d’origine et ne modifie que les métadonnées de forme ou de foulée, elle est donc bon marché mais les mutations se propagent. Une copie alloue une nouvelle mémoire et est indépendante. Le découpage et le « remodelage » renvoient généralement des vues ; une indexation sophistiquée et .copy() renvoient des copies. Utilisez arr.base pour vérifier si un tableau est une vue.
Comment rendre les résultats NumPy reproductibles ?
Utilisez np.random.default_rng(seed) au lieu de l’ancien global np.random.seed, épinglez la version NumPy dans votre environnement et enregistrez le type et la forme avec vos sorties. Conservez les tableaux avec np.save plutôt que CSV pour conserver exactement le type. Pour les tests, comparez avec np.testing.assert_allclose et une tolérance explicite.
Questions fréquentes
Qu'est-ce que le traitement des données NumPy ?
Le traitement des données NumPy implique l'utilisation du ndarray de la bibliothèque NumPy pour charger, nettoyer, transformer et réduire les données numériques. Il couvre la lecture de tableaux à partir de fichiers, la gestion des valeurs manquantes avec des fonctions compatibles NaN, le remodelage et la diffusion, ainsi que l'agrégation le long des axes. Étant donné que la plupart des bibliothèques scientifiques Python s'appuient sur NumPy, il s'agit de la couche fondamentale des pipelines numériques.
NumPy est-il plus rapide que les pandas pour le traitement des données ?
NumPy est plus rapide pour les tableaux numériques homogènes car il fonctionne directement sur la mémoire contiguë sans surcharge d'index ou de répartition de types. pandas est plus rapide à écrire et mieux adapté aux données tabulaires étiquetées de type mixte. Pour les calculs numériques volumineux, la conversion d'un DataFrame pandas en un tableau NumPy avec .to_numpy() et le traitement y sont une optimisation courante.
Comment gérer les données manquantes dans NumPy ?
Les tableaux à virgule flottante représentent les valeurs manquantes sous la forme np.nan, et NumPy fournit np.nanmean, np.nanstd, np.nansum et np.isnan pour travailler avec elles. Les tableaux d'entiers ne peuvent pas stocker NaN, donc convertissez-les en flottant ou utilisez une valeur sentinelle plus un masque booléen. Les tableaux masqués via np.ma offrent une alternative plus structurée.
NumPy peut-il traiter des données plus volumineuses que la RAM ?
Oui, en utilisant np.memmap pour mapper un fichier disque dans l'espace d'adressage, ou en lisant les ensembles de données HDF5 en morceaux avec h5py. Les deux approches limitent la mémoire maximale. Pour le traitement parallèle ou distribué sur plusieurs machines, Dask et Zarr étendent le même modèle de tableau au-delà d'un seul nœud.
Quelle est la différence entre une vue et une copie dans NumPy ?
Une vue partage la mémoire tampon du tableau d'origine et ne modifie que les métadonnées de forme ou de foulée, elle est donc bon marché mais les mutations se propagent. Une copie alloue une nouvelle mémoire et est indépendante. Le découpage et le remodelage renvoient généralement des vues ; une indexation sophistiquée et .copy() renvoient des copies. Utilisez arr.base pour vérifier si un tableau est une vue.
Comment rendre les résultats NumPy reproductibles ?
Utilisez np.random.default_rng(seed) au lieu de l'ancien np.random.seed global, épinglez la version NumPy dans votre environnement et enregistrez le type et la forme avec vos sorties. Conservez les tableaux avec np.save plutôt que CSV pour conserver exactement le type. Pour les tests, comparez avec np.testing.assert_allclose et une tolérance explicite.
Apprenez Python en codant dans votre navigateur
Cours interactifs Python et science des données que vous codez directement dans le navigateur