L’ingénierie et l’analyse exploratoire de données contemporaines reposent massivement sur l’écosystème open source de Python, au sein duquel la bibliothèque Pandas occupe une position hégémonique. Conçue initialement pour répondre aux exigences rigoureuses de la modélisation quantitative en finance par Wes McKinney, Pandas fournit des structures de données sophistiquées et hautement optimisées permettant de manipuler des ensembles de données tabulaires à deux dimensions. Parmi les opérations matricielles les plus courantes auxquelles sont confrontés les scientifiques des données, les statisticiens et les ingénieurs logiciels figure l’agrégation transversale, et plus spécifiquement le calcul de la moyenne arithmétique sur un sous-ensemble défini de variables. Bien que cette tâche puisse sembler élémentaire au premier abord, son exécution méthodique soulève des considérations fondamentales relatives à la disposition de la mémoire, à la préservation de la typologie des données, à la gestion probabiliste des valeurs manquantes et à l’intégrité statistique des inférences qui en découlent.
Le calcul de la moyenne sur des colonnes arbitrairement sélectionnées implique une maîtrise approfondie des mécanismes d’indexation, de découpage et de réduction dimensionnelle propres à Pandas et à son moteur sous-jacent, NumPy. Dans un contexte expérimental ou industriel, agréger aveuglément l’ensemble des colonnes d’un tableau de données expose le praticien à des biais cognitifs et analytiques sévères, tels que l’inclusion involontaire d’identifiants uniques, de variables temporelles ou de descripteurs catégoriels mal encodés. De surcroît, la variabilité des échelles de mesure et l’hétérogénéité des distributions imposent une sélection rigoureuse, programmatique ou déterministe, des attributs devant composer les indicateurs synthétiques. L’enjeu dépasse ainsi la simple invocation d’une méthode de calcul : il s’agit de structurer des pipelines de transformation robustes, déterministes et performants, capables de traiter des millions d’enregistrements sans compromettre les ressources computationnelles.
Ce guide exhaustif a pour vocation d’analyser en profondeur l’ensemble des méthodologies permettant d’extraire, d’isoler et de calculer la moyenne de colonnes sélectionnées au sein d’un DataFrame Pandas. Depuis les postulats algébriques de la réduction dimensionnelle jusqu’aux architectures modernes de traitement haute performance, nous explorerons les nuances syntaxiques des accesseurs de référence, les stratégies avancées de filtrage lexical et dynamique, les paradigmes de traitement des lacunes d’observation, ainsi que les implications de l’empreinte mémoire sur le temps d’exécution. Destiné aux chercheurs et développeurs exigeants, cet exposé articulera rigueur conceptuelle, analyse microscopique des paramètres d’exécution et préceptes d’ingénierie logicielle pour vous doter d’une expertise totale sur cette facette centrale de la manipulation de données vectorisées.
1. Introduction théorique et fondements de l’agrégation dans Pandas
1.1 Structure matricielle des DataFrames et dimensionnalité
Pour appréhender avec exactitude les calculs transversaux au sein de la bibliothèque Pandas, il est impératif d’examiner l’architecture interne des structures de données fondamentales que sont la Series et le DataFrame. Sur le plan de l’algèbre computationnelle, un DataFrame s’apparente à une matrice bidimensionnelle dotée d’étiquettes sur ses deux axes. L’axe vertical, formellement désigné par axis=0 ou l’index des lignes, correspond aux observations individuelles de l’échantillon. L’axe horizontal, désigné par axis=1 ou l’index des colonnes, correspond aux variables, attributs ou dimensions mesurées pour chaque entité. Cette distinction géométrique est critique : une opération d’agrégation appliquée le long d’un axe entraîne la disparition structurelle de cet axe par projection, comprimant ainsi la matrice dans un hyperplan de dimension inférieure.
Chaque colonne d’un DataFrame constitue une instance de Series, laquelle encapsule un tableau unidimensionnel typé géré par le module ndarray de NumPy ou, dans les versions récentes de Pandas, par les extensions de type d’Apache Arrow. Alors que les calculs statistiques classiques en apprentissage automatique et en économétrie sont traditionnellement menés le long de l’axe vertical (visant à dégager les propriétés distributionnelles d’une variable à travers l’ensemble des observations), le calcul de moyennes sur des colonnes sélectionnées exige une inversion de perspective. L’opérateur doit traverser horizontalement la mémoire pour synthétiser, pour une observation donnée, les valeurs issues de multiples colonnes distinctes. Cette transversalité introduit des considérations liées à l’alignement strict des index, mécanisme fondamental par lequel Pandas fait correspondre automatiquement les éléments sur la base de leurs étiquettes plutôt que de leur position absolue dans le tampon mémoire.
Dans les sciences quantitatives, notamment en psychométrie, en bio-informatique et en finance computationnelle, l’opération de réduction dimensionnelle transversale répond à la nécessité théorique de synthétiser des signaux dispersés en scores composites. La construction d’un score de propension, d’un indice de solvabilité ou d’un facteur latent nécessite fréquemment d’isoler un sous-espace vectoriel précis de la matrice originale afin d’en extraire la tendance centrale par observation. Le non-alignement des étiquettes ou une mauvaise appréciation de l’orientation de l’axe de réduction entraîne inévitablement des erreurs silencieuses, l’interpréteur Python exécutant une réduction verticale là où une synthèse horizontale était requise, modifiant radicalement la topologie des tenseurs résultants.
1.2 Définition formelle de la moyenne arithmétique appliquée aux sous-ensembles
Sur le plan mathématique formel, considérons un tableau de données représenté par une matrice X de dimension n × p, où n désigne le nombre total d’observations (lignes) et p le nombre de variables observées (colonnes). Soit un sous-ensemble d’indices de colonnes sélectionné S inclus dans l’ensemble des indices {1, 2, …, p}, de cardinalité k = |S|, où k ≤ p. Pour chaque observation indicée par i (avec 1 ≤ i ≤ n), le vecteur des variables sélectionnées est noté x_{i, S}. La moyenne arithmétique restreinte à ce sous-ensemble s’exprime selon l’équation canonique suivante : la somme de tous les éléments x_{i, j} pour j appartenant à S, divisée par le nombre effectif de variables k.
Cette formulation déterministe devient considérablement plus complexe dans les applications réelles en raison de la nature hétérogène des données tabulaires. Contrairement à une agrégation globale aveugle qui sommerait indistinctement toutes les entrées disponibles pour un enregistrement, l’agrégation conditionnelle sur un sous-ensemble implique une décision théorique sur l’inclusion de variables de natures divergentes. La combinatoire de variables continues, d’échelles ordinales ou de mesures quantitatives discrètes au sein d’une même opération arithmétique peut violer les postulats de base de la théorie de la mesure. Si des variables mesurées sur des échelles dissemblables sont fusionnées sans standardisation préalable, la variable présentant la plus forte variance relative dominera indûment la moyenne composite calculée.
De surcroît, la préservation de l’intégrité des types de données au sein du schéma du DataFrame représente un défi mathématique et informatique non négligeable. Lors du calcul de la moyenne sur des colonnes sélectionnées contenant des entiers de faible précision (par exemple int8 ou int16), l’opération arithmétique exige une promotion de type vers des nombres à virgule flottante (généralement float64) afin d’éviter tout phénomène de troncature numérique ou de dépassement de capacité (overflow). L’environnement Pandas gère nativement cette promotion implicite, mais la traçabilité des représentations numériques en virgule flottante selon la norme IEEE 754 doit être surveillée pour prévenir l’accumulation d’erreurs d’arrondi lors du traitement de millions de lignes.
2. Anatomie de la méthode .mean() dans l’environnement Pandas
2.1 Examen critique du paramètre axis
La méthode mean() constitue l’interface programmatique standard pour l’exécution d’agrégations arithmétiques au sein des objets DataFrame et Series de Pandas. Sa signature regroupe plusieurs paramètres déterminants, au premier rang desquels figure l’argument axis. Par défaut, la méthode est paramétrée sur axis=0 (ou sa version textuelle axis=’index’), ce qui enjoint le moteur de calcul d’itérer le long des colonnes pour produire une moyenne par variable à travers toutes les lignes. Pour inverser cette logique et calculer la moyenne des colonnes sélectionnées pour chaque enregistrement individuel, l’analyste doit explicitement assigner la valeur axis=1 ou axis=’columns’. Cette instruction ordonne la condensation de la dimension horizontale en un vecteur colonne unidimensionnel.
L’impact de ce choix sur les performances d’exécution est substantiel en raison des contraintes physiques de l’architecture matérielle et de la gestion de la mémoire cache. Dans les versions sous-jacentes de NumPy, les tableaux sont fréquemment alloués selon un agencement linéaire en mémoire contiguë par ligne (le modèle dit C-contiguous) ou par colonne (le modèle Fortran-contiguous). Le gestionnaire de blocs de Pandas (BlockManager), qui regroupe les colonnes de même type primitif sous forme de matrices NumPy multidimensionnelles, optimise historiquement les accès par colonne. Par conséquent, l’exécution d’une moyenne horizontale (axis=1) requiert de parcourir la mémoire transversalement, ce qui peut engendrer un taux élevé de défauts de cache (cache misses) si les colonnes ne résident pas dans des zones mémoires contiguës. Les itérateurs internes codés en langage C ou Cython doivent alors effectuer des calculs de décalage d’adresses (strides) plus sophistiqués.
Sur le plan structurel, l’application de mean(axis=1) transforme un DataFrame de dimension (n, k) en un objet Series de dimension (n,), dont l’index reste rigoureusement identique à l’index des lignes du DataFrame d’origine. Cette invariance de l’index constitue une garantie architecturale essentielle de Pandas : elle autorise la réintégration immédiate et vectorisée du vecteur de sortie au sein de la structure de données parente sans nécessiter d’opération de fusion (merge) ou d’alignement explicite, simplifiant drastiquement les flux de transformation de données.
2.2 Gestion des paramètres skipna et numeric_only
Le second levier opérationnel critique de la méthode mean() réside dans le paramètre booléen skipna, configuré par défaut à True. Ce paramètre dicte le comportement de l’algorithme face aux données manquantes, représentées conventionnellement par des balises NaN (Not a Number) ou des objets None. Lorsque skipna=True est actif, Pandas omet systématiquement les entrées non définies lors de l’évaluation de la somme et adapte dynamiquement le diviseur au nombre réel de valeurs observables pour chaque ligne. Si ce mécanisme prévient l’échec computationnel, il modifie subtilement le fondement statistique de l’estimateur, car le dénominateur devient une variable dépendante de la complétude locale des données plutôt qu’une constante fixe pour l’ensemble des observations.
À l’inverse, l’assignation de skipna=False impose une politique d’évaluation stricte : la moindre valeur manquante identifiée au sein des colonnes sélectionnées pour une ligne donnée propage inexorablement la valeur NaN à l’ensemble du résultat agrégé de cette observation. Cette approche est particulièrement prisée dans les protocoles scientifiques rigides où une mesure incomplète invalide totalement la validité de l’observation globale. D’un point de vue statistique, ignorer la présence d’une valeur absente sans modéliser le mécanisme de disparition (qu’il soit manquant complètement au hasard, MCAR, ou manquant au hasard, MAR) risque d’introduire des biais d’échantillonnage non négligeables lors de l’interprétation finale de la moyenne calculée.
Parallèlement, le paramètre numeric_only joue un rôle pivot dans la robustesse du code, particulièrement à la lumière des évolutions introduites depuis la version 2.0 de Pandas. Historiquement, Pandas tentait de déterminer silencieusement quelles colonnes pouvaient être agrégées et ignorait les types non numériques lors d’une tentative de calcul de moyenne. Désormais, numeric_only est défini sur False par défaut dans de nombreuses fonctions ou impose une déclaration explicite. Tenter d’exécuter une moyenne sur un sous-ensemble comportant des colonnes contenant des chaînes de caractères (object ou string) lève une exception systématique de type TypeError. L’analyste doit donc impérativement s’assurer que son sous-ensemble ne contient que des types arithmétiquement exploitables, ou configurer numeric_only=True pour forcer le moteur d’exécution à écarter en amont les descripteurs non calculables.
3. Calcul de la moyenne globale de toutes les colonnes par observation
3.1 Syntaxe fondamentale et affectation vectorisée
Avant d’aborder les sélections complexes, il convient d’analyser le cas fondamental où l’intégralité des variables numériques d’un tableau doit être synthétisée. Dans une configuration théorique où un DataFrame contiendrait exclusivement des variables continues normalisées et homogènes, l’instruction se déploie sans artifice sous la forme df.mean(axis=1). L’assignation de cette Series résultante au DataFrame source s’effectue par le truchement de la création d’une nouvelle clé d’index de colonne, matérialisée par l’expression vectorisée df[‘moyenne_globale’] = df.mean(axis=1). Ce mécanisme tire parti des moteurs vectorisés sous-jacents, éliminant tout recours à des boucles explicites en Python qui dégraderaient catastrophiquement les performances.
L’évaluation empirique préalable de l’homogénéité des distributions représente une étape méthodologique indissociable de cette syntaxe. Lorsque le calcul s’applique globalement, l’analyste doit mobiliser la méthode descriptive df.describe() afin de vérifier les métriques de dispersion transversale : les écarts-types, les valeurs minimales et maximales, ainsi que les quartiles de chaque dimension. Si une variable présente une dispersion d’un ordre de grandeur supérieur aux autres en raison d’une unité de mesure divergente (par exemple des revenus annuels en devises agrégés avec des âges ou des ratios de pourcentages), la moyenne calculée sera mathématiquement dénuée de sens substantiel.
L’affectation vectorisée garantit en outre que les propriétés de diffusion (broadcasting) de NumPy sont pleinement exploitées. Lors de l’assignation de la colonne résultante, Pandas vérifie automatiquement l’alignement des étiquettes de l’index horizontal avec celles du tableau hôte. Même si l’ordre sous-jacent des lignes venait à être altéré lors d’une étape de pré-traitement, l’intégrité référentielle des données est garantie par ce mécanisme d’alignement formel, rendant l’affectation insensible aux décalages physiques d’adresses en mémoire.
3.2 Limitations méthodologiques du calcul exhaustif aveugle
Appliquer l’opérateur d’agrégation de manière indiscriminée sur un DataFrame industriel ou scientifique constitue une faute d’ingénierie critique. Dans la quasi-totalité des architectures de bases de données relationnelles ou d’entrepôts de données, les tables comportent une multitude de colonnes techniques indispensables à la gouvernance mais toxiques pour le calcul statistique. Parmi celles-ci figurent les clés primaires entières (identifiants uniques d’utilisateurs ou de transactions), les horodatages convertis en entiers d’époque Unix, les versions de schémas ou encore les variables de contrôle expérimentales.
Si ces variables numériques non substantielles ne sont pas préalablement écartées, l’instruction df.mean(axis=1) les incorpore dans le numérateur et le dénominateur de chaque ligne. Le résultat produit est alors complètement contaminé : la moyenne synthétique reflète majoritairement l’amplitude de l’identifiant technique plutôt que la mesure physiologique, financière ou comportementale sous-jacente. Cette situation est d’autant plus insidieuse qu’elle n’engendre aucune exception logicielle lors de l’exécution, produisant des données corrompues de manière totalement silencieuse au sein du pipeline d’apprentissage ou de reporting.
Au-delà des métadonnées et clés techniques, la présence de colonnes affichant de fortes variances non contrôlées perturbe profondément l’analyse statistique. Dans le cadre de la construction d’un indicateur de performance, l’agrégation non pondérée d’attributs dont la variance s’étend de 0,01 à 10 000 engendre une instabilité numérique majeure. C’est précisément pour juguler ces écueils fondamentaux que l’isolement déterministe et strict d’un sous-ensemble ciblé de colonnes s’impose comme une nécessité absolue pour tout analyste quantitatif rigoureux.
4. Sélection explicite de colonnes via l’indexation par liste
4.1 Technique d’indexation double crochet : df[[‘col1’, ‘col2’]]
L’approche la plus canonique, lisible et répandue pour isoler des variables cibles dans Pandas réside dans l’utilisation de l’indexation par double crochet, à laquelle on transmet une liste explicite d’étiquettes de colonnes sous forme de chaînes de caractères. La syntaxe df[[‘variable_A’, ‘variable_B’, ‘variable_C’]].mean(axis=1) établit une frontière hermétique entre les colonnes analytiques d’intérêt et le reste des métadonnées du DataFrame. En restreignant explicitement les opérandes aux labels stipulés, le praticien élimine structurellement tout risque de pollution statistique par des attributs tiers.
Sur le plan de l’architecture logicielle de Pandas, cette sélection opère une projection qui génère soit une vue (view), soit une copie superficielle (shallow copy) des colonnes requises. Lorsque l’indexation par liste extrait des colonnes issues de différents blocs de mémoire sous-jacents, Pandas est généralement contraint de matérialiser un nouveau DataFrame intermédiaire avant d’appliquer l’algorithme d’agrégation transversale. Bien que cette copie génère une légère allocation de mémoire résidente, elle offre des garanties d’isolation indispensables dans les environnements multi-fils ou dans le cadre de transformations séquentielles complexes où l’intégrité de la structure originale doit demeurer immuable.
L’avantage prépondérant de l’indexation par liste explicite se manifeste dans la lisibilité et l’auditabilité du code. Dans un projet de recherche soumis à des exigences de reproductibilité scientifique, la déclaration manifeste des variables composant chaque dimension statistique assure qu’aucun changement inopiné dans le schéma de la base de données source (comme l’insertion d’une nouvelle colonne par l’administrateur système) ne viendra altérer rétroactivement la formule de calcul. Cette explicitation confère au script une robustesse contractuelle pérenne.
4.2 Affectation sécurisée du score moyen calculé
Une fois le calcul horizontal opéré sur le sous-ensemble de variables extrait par indexation, la valeur agrégée doit être intégrée dans la structure maîtresse. L’opération s’écrit formellement df[‘score_synthetique’] = df[[‘col1’, ‘col2’, ‘col3’]].mean(axis=1). Il est impératif d’utiliser une nomenclature de variable transparente et standardisée, qui documente idéalement la nature de l’opération (par exemple en ajoutant le préfixe mean_ ou le suffixe _composite), facilitant ainsi le travail des ingénieurs aval chargés de la validation statistique des modèles.
Cette étape d’affectation requiert une vigilance technique particulière pour prévenir l’apparition de l’avertissement célèbre mais souvent mal compris : SettingWithCopyWarning. Si l’analyste applique l’extraction et l’affectation sur un sous-ensemble filtré sans avoir préalablement cloné l’objet via une commande explicite telle que .copy(), Pandas ne peut déterminer avec certitude si l’assignation modifie l’objet original ou une tranche mémoire éphémère. Pour neutraliser définitivement ce comportement, le calcul doit toujours être affecté soit directement sur le DataFrame racine initialement instancié, soit sur une copie détachée formellement déclarée.
La validation de la cohérence dimensionnelle constitue le corollaire de cette affectation sécurisée. Étant donné que la Series résultante partage de manière intrinsèque l’index du tableau ayant fait l’objet de l’extraction, la réinsertion s’effectue sans aucune disparité d’alignement, y compris en présence d’index non contigus ou de clés d’indexation temporelles discontinues. Cette propriété d’adhérence garantit qu’aucune valeur n’est imputée à une observation erronée par simple décalage d’offset.
5. Sélection avancée au moyen des accesseurs .loc et .iloc
5.1 Utilisation de .loc pour le ciblage par labels et plages d’étiquettes
L’accesseur d’indexation par étiquettes .loc représente l’un des mécanismes les plus puissants et expressifs offerts par l’API de Pandas. Sa structure accepte deux dimensions séparées par une virgule : la première spécifie le masque ou l’ensemble des lignes à sélectionner, tandis que la seconde cible les colonnes par leurs étiquettes. Pour calculer la moyenne d’une plage continue de variables, la syntaxe df.loc[:, ‘question_1′:’question_10’].mean(axis=1) permet d’agréger toutes les colonnes situées physiquement entre les étiquettes désignées inclusivement, éliminant ainsi le besoin de rédiger une liste exhaustive et fastidieuse de noms de variables.
Une particularité technique fondamentale de l’opérateur de découpage (slicing) de .loc réside dans l’inclusion stricte de la borne supérieure. Contrairement aux conventions usuelles du découpage séquentiel en Python pur ou au sein des listes d’index entiers, la colonne marquant la fin de la tranche est expressément incluse dans le calcul. Cette spécificité impose une vigilance rigoureuse lors de la refactorisation de schémas de données : si l’ordre relatif des colonnes dans le DataFrame vient à être modifié lors d’une extraction SQL antérieure, la tranche délimitée par ‘question_1′:’question_10’ pourrait englober par mégarde des attributs hétérogènes accidentellement déplacés entre ces deux balises.
L’accesseur .loc se distingue également par sa capacité à coupler de manière atomique le calcul transversal avec des prédicats conditionnels appliqués sur les lignes. Par exemple, il est trivial d’isoler un sous-groupe démographique spécifique pour n’évaluer la moyenne que sur ce segment : df.loc[df[‘age’] >= 18, ‘score_A’:’score_Z’].mean(axis=1). Dans ce scénario, les lignes ne répondant pas au critère booléen ne subissent pas le calcul ou peuvent être assignées à des valeurs manquantes, optimisant la chaîne de traitement en évitant des calculs superflus sur des observations hors champ d’étude.
5.2 Utilisation de .iloc pour la sélection positionnelle pure
Complémentaire direct de .loc, l’accesseur .iloc s’abstrait totalement des étiquettes textuelles pour baser son indexation exclusivement sur les positions ordinales entières des colonnes en mémoire, indexées à partir de 0. Pour calculer la moyenne sur un échantillon discontinu de variables, l’analyste emploie l’instruction df.iloc[:, [0, 2, 4, 7]].mean(axis=1). De même, une plage séquentielle continue s’exprime par le découpage positionnel classique df.iloc[:, 3:12].mean(axis=1), lequel obéit scrupuleusement aux conventions Python standards en excluant la borne supérieure (la douzième colonne est donc omise du sous-ensemble).
L’usage de .iloc présente des avantages majeurs dans les cas où les données sont anonymisées, dépourvues d’en-têtes textuels ou issues de formats matriciels bruts dépourvus de métadonnées de schémas (fichiers plats issus d’instruments scientifiques, sorties brutes de capteurs IoT). En opérant uniquement par déplacement d’index entiers, .iloc court-circuite le temps de calcul lié à la recherche lexicographique dans la table de hachage de l’objet Index de Pandas, ce qui permet un gain de performance marginal mais mesurable lors de boucles répétitives de prétraitement.
En contrepartie, le recours à la sélection positionnelle pure introduit un risque majeur d’obsolescence et de rupture du code. Toute altération structurelle dans l’ordre d’ingestion des flux de données amont décale les indices de position, conduisant .iloc à agréger des colonnes totalement imprévues sans déclencher d’alerte syntaxique. Par conséquent, il est formellement recommandé de réserver l’utilisation de .iloc à des scripts de parsing locaux et immédiats, ou à des jeux de données hautement standardisés où la structure positionnelle est scellée de manière contractuelle et invariable.
6. Sélection dynamique et programmatique de colonnes
6.1 Filtrage lexical avec la méthode .filter()
Dans les jeux de données complexes comportant plusieurs centaines de variables issues de sondages, de questionnaires psychométriques standardisés ou de métriques de télémétrie horodatées, la sélection manuelle ou par tranches devient insoutenable. Pandas propose une solution élégante à cette problématique par l’intermédiaire de la méthode filter(), laquelle offre un mécanisme d’interrogation lexical hautement sophistiqué pour extraire des sous-ensembles de colonnes selon des critères de sous-chaînes ou d’expressions régulières.
Le paramètre like permet d’isoler instantanément toutes les variables contenant une séquence textuelle invariable. À titre d’exemple, l’instruction df.filter(like=’anxiete_’).mean(axis=1) extrait dynamiquement chaque colonne dont le label intègre ce radical pour en calculer la moyenne transversale. Pour les cas d’usage requérant une complexité structurelle supérieure, l’argument regex autorise le passage de motifs d’expressions régulières régies par le standard POSIX/Python. La syntaxe df.filter(regex=r’^item_(0[1-9]|10)$’).mean(axis=1) permet d’agréger précisément les items codifiés de 01 à 10, tout en ignorant automatiquement les items subsidiaires ou dérivés portant des dénominations proches.
Sur le plan des performances algorithmiques, la méthode filter() itère sur la liste immuable des colonnes du DataFrame sans copier les données réelles durant la phase d’évaluation des motifs réguliers. Une fois le sous-ensemble identifié, la méthode renvoie une structure projetée sur laquelle mean(axis=1) s’exécute de manière vectorisée. Cette abstraction découple l’architecture du code des spécificités du jeu de données : si de nouveaux items respectant la convention de nommage sont intégrés ultérieurement dans la source amont, le pipeline les capture sans nécessiter la moindre refactorisation manuelle.
6.2 Compréhension de listes et inspection des métadonnées de colonnes
Bien que la méthode filter() soit remarquable pour des analyses fondées exclusivement sur la nomenclature des labels, elle s’avère incapable d’évaluer d’autres propriétés intrinsèques des séries comme leur nature typologique ou leur complétude. C’est ici qu’intervient l’inspection programmatique combinée aux compréhensions de listes (list comprehensions) natives de Python. Cette technique offre une granularité décisionnelle illimitée pour filtrer les variables en amont de l’agrégation transversale.
Une compréhension de liste permet d’analyser simultanément des critères nominaux et logiques, comme l’illustre la formulation suivante :
- Extraction par préfixe ou suffixe : l’analyste inspecte les attributs textuels à l’aide de méthodes natives comme str.startswith() ou str.endswith().
- Filtrage par typologie matérielle : en s’appuyant sur l’accesseur select_dtypes(include=[np.number]), le script écarte structurellement toute variable textuelle, booléenne ou catégorielle pour ne retenir que les colonnes compatibles avec la moyenne arithmétique.
- Combinaison multicritère avancée : il devient trivial de formuler des filtres conditionnels complexes, par exemple extraire toutes les colonnes débutant par le radical ‘score_’ dont le type primitif est un flottant et dont le taux de complétude excède un seuil déterminé.
Le vecteur d’étiquettes obtenu via cette compréhension de liste est ensuite passé directement au DataFrame par indexation explicite : df[[col for col in df.columns if col.startswith(‘test_’) and df[col].dtype == ‘float64’]].mean(axis=1). Cette approche modulaire s’intègre harmonieusement au sein d’architectures orientées objet et de pipelines de nettoyage automatisé de données massives, conférant une résilience totale aux variations de schémas.
7. Traitement rigoureux des données manquantes et imputation
7.1 Impact du paramètre skipna sur la représentativité des moyennes
L’omniprésence de données manquantes au sein des bases d’observation modernes constitue l’un des défis les plus pernicieux de la statistique appliquée. Comme introduit précédemment, l’argument skipna=True autorise Pandas à calculer la moyenne arithmétique sur la seule base des entrées effectivement renseignées pour chaque ligne. Cependant, les implications méthodologiques de ce paramétrage par défaut sont souvent occultées par les praticiens. Lorsqu’un individu sur un panel de dix questions n’a répondu qu’à deux d’entre elles, sa moyenne est calculée sur un dénominateur de deux, tandis qu’un individu ayant répondu à l’intégralité du test verra sa somme divisée par dix.
Cette plasticité du dénominateur altère drastiquement la variance relative des scores composites générés. Les observations comportant de fortes lacunes présentent une variance de score artificiellement accrue, étant basées sur un sous-échantillon d’items excessivement restreint, ce qui viole fréquemment l’hypothèse d’homoscédasticité nécessaire aux modélisations économétriques subséquentes. À l’extrême opposé, forcer skipna=False engendre une perte drastique de puissance statistique en éliminant ou en rendant nulles toutes les lignes présentant au moins une omission, ce qui peut décimer un échantillon expérimental.
Une stratégie robuste consiste à établir un seuil contractuel de complétude minimale par observation avant d’autoriser le calcul de la moyenne. Pandas permet d’évaluer ce critère par la combinaison des méthodes isna() ou notna() avec une sommation horizontale : df[colonnes].notna().sum(axis=1). L’analyste peut alors formaliser un masque logique garantissant que la moyenne ne sera calculée que pour les lignes disposant d’au moins 70 % ou 80 % de réponses valides, garantissant un équilibre optimal entre représentativité individuelle et préservation du volume d’échantillonnage.
7.2 Imputation préalable et calcul conditionnel
Pour pallier les distorsions inhérentes à l’usage simpliste de skipna=True, la mise en œuvre de protocoles d’imputation préalable sur le sous-ensemble sélectionné s’avère fréquemment indispensable. L’analyste peut déployer une vaste gamme de techniques correctives, allant de l’imputation déterministe simple par la médiane de l’item à des approches d’imputation stochastique ou multiple issues du cadre méthodologique de Rubin.
Dans un contexte d’imputation locale simple, la méthode fillna() peut être confinée de façon très stricte aux seules colonnes sélectionnées, empêchant la modification collatérale du reste de la base de données :
- Imputation par la moyenne de la variable : chaque valeur manquante d’une colonne est substituée par la moyenne transversale globale de cette même colonne via df[cols].fillna(df[cols].mean()) avant le calcul horizontal par observation.
- Imputation par interpolation horizontale : pour des séries chronologiques ou spatiales continues observées par ligne, l’appel à df[cols].interpolate(axis=1) permet d’estimer les valeurs manquantes d’après les colonnes adjacentes immédiates.
- Modélisation prédictive locale : l’utilisation d’algorithmes plus perfectionnés tels que les k-plus proches voisins (KNNImputer) ou les forêts aléatoires itératives (IterativeImputer de scikit-learn) sur le sous-ensemble dédié.
L’intégration de telles démarches requiert une documentation méthodologique méticuleuse afin de préserver la traçabilité scientifique des transformations. Il est d’usage d’effectuer une analyse de sensibilité systématique en comparant la distribution du score composite issu d’un calcul direct avec skipna=True et celle émanant de la structure imputée, afin d’identifier tout artefact d’estimation induit par la manipulation des données manquantes.
8. Calcul de moyennes pondérées pour sous-ensembles de colonnes
8.1 Formulation vectorielle de la moyenne pondérée avec NumPy
La moyenne arithmétique simple postule une équivalence d’importance absolue entre toutes les variables sélectionnées. Or, dans de multiples disciplines quantitatives, les variables contribuent de façon inégale au concept théorique mesuré. Qu’il s’agisse de coefficients de pondération attribués aux actifs financiers d’un portefeuille, de crédits académiques accordés à des examens universitaires ou de poids factoriels émanant d’une analyse en composantes principales (ACP), la moyenne arithmétique pondérée s’impose comme la réponse analytique appropriée.
La méthode native df.mean() ne disposant pas d’un paramètre autorisant l’injection de poids par colonne, le recours à la bibliothèque NumPy représente la solution d’ingénierie la plus élégante et performante. La fonction np.average() accepte explicitement un argument weights. L’exécution vectorisée prend alors la forme suivante :
poids = [0.1, 0.2, 0.4, 0.3]
df[‘moyenne_ponderee’] = np.average(df[[‘v1’, ‘v2’, ‘v3’, ‘v4’]], axis=1, weights=poids)
Cette approche tire parti du calcul matriciel compilé en langage C sous-jacent. La fonction vérifie que la dimension du vecteur de pondération correspond exactement au nombre de colonnes isolées dans le sous-ensemble. La normalisation des poids est prise en charge nativement : si la somme des coefficients n’égale pas l’unité, np.average procède silencieusement à la division par la somme cumulée des poids, garantissant l’intégrité de l’échelle d’arrivée. Il convient toutefois de souligner une limitation critique : np.average ne prend pas en charge l’omission automatique des NaN (absence d’équivalent direct à skipna=True) ; la moindre donnée manquante au sein d’une ligne entraînera la propagation de la valeur NaN pour toute la ligne.
8.2 Approche purement Pandas par multiplication vectorielle
Pour surmonter la rigidité de NumPy vis-à-vis des valeurs manquantes tout en conservant l’expressivité de Pandas, une implémentation purement vectorisée exploitant l’algèbre tabulaire de Pandas s’avère souvent supérieure. Cette technique s’articule autour de la combinaison coordonnée de la méthode de multiplication élément par élément mul() et de la méthode de sommation horizontale sum().
Soit une Series ou un dictionnaire définissant les poids associés à chaque étiquette de colonne, l’opération s’articule selon l’enchaînement canonique suivant :
cols = [‘critere_A’, ‘critere_B’, ‘critere_C’]
poids = pd.Series({‘critere_A’: 2.0, ‘critere_B’: 3.0, ‘critere_C’: 5.0})
score = df[cols].mul(poids, axis=1).sum(axis=1) / poids.sum()
Ce formalisme présente une résilience architecturale remarquable grâce au mécanisme d’alignement par labels propre à Pandas. Lors de l’invocation de mul(poids, axis=1), le moteur fait correspondre automatiquement chaque coefficient de pondération à la colonne idoine en se basant sur le label textuel, rendant l’opération insensible à l’ordre d’agencement des éléments au sein de l’objet de poids. De plus, si l’on souhaite gérer dynamiquement les valeurs manquantes sans biaiser le diviseur, il est aisé d’adapter le calcul :
denominateur = df[cols].notna().mul(poids, axis=1).sum(axis=1)
df[‘score_pondere_robuste’] = df[cols].mul(poids, axis=1).sum(axis=1) / denominateur
Dans ce modèle avancé, le diviseur correspond scrupuleusement à la somme des poids des variables effectivement observées pour chaque ligne individuelle, réalisant ainsi une moyenne pondérée dynamique et hautement adaptative face à l’incomplétude du recueil de données.
9. Étude de cas appliquée : Construction de scores psychométriques
9.1 Agrégation d’échelles de Likert et scores composites
Pour illustrer la mise en œuvre empirique de ces principes méthodologiques, considérons une étude de cas représentative issue des sciences comportementales ou du marketing quantitatif : la construction d’un indice composite d’évaluation de la satisfaction ou de l’anxiété au travail à partir d’un ensemble d’items mesurés sur une échelle ordinale de Likert graduée de 1 à 5. Le protocole implique l’agrégation de dix variables baptisées conventionnellement item_01 à item_10.
Une contrainte psychométrique majeure réside dans la présence fréquente d’items inversés, formulés de manière négative afin de limiter les biais d’acquiescement chez les répondants. Avant d’engager le moindre calcul de moyenne transversale, ces variables doivent subir une transformation affine de redressement d’échelle. Pour une échelle de 1 à 5, l’inversion d’un score x s’effectue selon la formule linéaire x_{inverse} = (Min + Max) – x = 6 – x. Au sein du DataFrame, cette opération s’exécute de façon vectorisée : df[[‘item_02’, ‘item_05’]] = 6 – df[[‘item_02’, ‘item_05’]].
Une fois les polarités des questions rigoureusement alignées pour converger vers un sens conceptuel univoque, l’analyste peut procéder à l’isolation du bloc de colonnes pour en extraire les différentes dimensions latentes (par exemple, les composantes cognitive, affective et comportementale de l’attitude). Chaque dimension fait alors l’objet d’un calcul de moyenne de sous-ensemble dédié :
- Composante cognitive : calculée sur les items 1, 3 et 4 via df[[‘item_01’, ‘item_03’, ‘item_04’]].mean(axis=1).
- Composante affective : calculée sur les items réalignés 2, 5 et 6 via df[[‘item_02’, ‘item_05’, ‘item_06’]].mean(axis=1).
- Score psychométrique global : moyenne synthétique transversale opérée sur la totalité des dix variables harmonisées.
Les scores bruts obtenus peuvent enfin être normalisés (par centrage-réduction ou transformation en scores standardisés Z) afin de permettre une interprétation relative des profils individuels par rapport à l’échantillon d’étalonnage normatif.
9.2 Contrôle de fidélité et validation statistique du score agrégé
L’agrégation transversale d’items psychométriques n’est scientifiquement légitime que si le sous-ensemble de colonnes retenu démontre une cohérence interne satisfaisante. Calculer la moyenne d’items non corrélés équivaut à agréger du bruit stochastique, aboutissant à un indicateur vide de validité de construit. L’indicateur standard de validation de cette cohérence est le coefficient Alpha de Cronbach (α).
L’évaluation mathématique de l’Alpha de Cronbach mobilise directement la matrice de covariance transversale du sous-ensemble de colonnes sélectionné. La formule dépend du nombre d’items k, de la somme des variances individuelles de chaque colonne, et de la variance de la somme (ou de la moyenne) transversale de toutes les colonnes. Si le coefficient résultant s’avère inférieur au seuil conventionnel de 0,70, la validité de l’échelle composite est sérieusement remise en cause, indiquant que certaines variables du sous-ensemble n’évaluent pas le même construit latent.
En parallèle, une étape de détection des profils de réponses invariables (les répondants ayant sélectionné systématiquement la même modalité sur tous les items) s’impose impérativement avant le calcul de la moyenne. Cela s’accomplit aisément en examinant la variance horizontale du sous-ensemble : df[cols].std(axis=1) == 0. Les lignes identifiées comme dépourvues de variance sont soit isolées pour inspection clinique, soit écartées de l’analyse, assurant ainsi que le score composite réinjecté dans les modèles de régression multivariée finaux ne souffre d’aucun biais méthodologique susceptible d’invalider les conclusions inférentielles de l’étude.
10. Optimisation des performances computationnelles et gestion de la mémoire
10.1 Downcasting et réduction de l’empreinte mémoire des colonnes
Dans le traitement de corpus massifs comprenant des millions d’enregistrements, la gestion microscopique de la mémoire vive devient un facteur critique conditionnant la faisabilité des calculs transversaux. Par défaut, lors de l’ingestion de données numériques, Pandas alloue quasi systématiquement le type float64 pour les valeurs réelles et int64 pour les entiers. Chaque cellule mobilise alors 8 octets de mémoire physique, ce qui amplifie considérablement l’empreinte globale du DataFrame et sature la bande passante du bus mémoire lors des itérations horizontales.
L’analyste quantitatif avisé procède à une réduction contrôlée de la précision typologique (technique dite de downcasting). La transformation de colonnes float64 en float32 divise par deux l’espace mémoire consommé par les variables sélectionnées, tout en préservant une précision d’environ 7 décimales significatives, ce qui est largement suffisant pour la majorité des sciences expérimentales et sociales. La méthode s’applique vectoriellement : df[cols] = df[cols].astype(np.float32). L’impact sur la consommation globale se mesure de manière empirique à l’aide de l’instruction df[cols].memory_usage(deep=True).sum().
Cette optimisation mémoire a une incidence directe et mesurable sur l’efficacité des caches de niveau 1 (L1) et de niveau 2 (L2) des microprocesseurs contemporains. En réduisant la taille des éléments constitutifs de chaque ligne, un plus grand nombre d’observations peut résider simultanément dans les lignes de cache à haute vitesse. Il en résulte une accélération marquée de l’opération transversale df[cols].mean(axis=1), le processeur passant moins de cycles d’attente à transférer les données depuis la mémoire centrale (RAM).
10.2 Parallélisation et alternatives pour mégadonnées (Big Data)
Lorsque les volumes de données s’étendent au-delà des capacités de traitement en mémoire d’un seul cœur de calcul, l’exécution séquentielle native de Pandas révèle ses goulets d’étranglement structurels. Pour contourner ces barrières, une première technique consiste à court-circuiter l’encapsulation de haut niveau de Pandas pour exécuter le calcul directement sur les tenseurs bruts via le moteur compilé de NumPy. L’extraction df[cols].to_numpy().mean(axis=1) élimine la surcharge liée à la gestion des index et permet des gains de temps d’exécution substantiels mesurables via le module de benchmarking %timeit.
Si la vitesse de NumPy demeure insuffisante ou si le jeu de données excède la capacité mémoire de la station de travail, il devient impératif de migrer vers des bibliothèques exploitant la vectorisation SIMD (Single Instruction, Multiple Data), le parallélisme multi-cœurs ou l’exécution différée (lazy evaluation) :
- Polars : moteur tabulaire moderne écrit en Rust, basé sur le modèle mémoire d’Apache Arrow. Polars exécute nativement les moyennes transversales de façon multithreadée avec une efficacité mémoire sans commune mesure avec Pandas, grâce à sa syntaxe vectorisée pl.mean_horizontal(‘col1’, ‘col2’, …).
- Dask DataFrame : framework distribuant les structures de données en partitions logiques réparties sur plusieurs cœurs ou nœuds d’un cluster, permettant d’exécuter l’instruction ddf[cols].mean(axis=1).compute() sur des téraoctets de données fragmentées sur disque.
- Numba : compilateur juste-à-temps (JIT) capable de transformer une boucle transversale Python décorée par @jit(nopython=True, parallel=True) en instructions machines natives parallélisées sur les registres vectoriels AVX-512.
L’adoption de ces solutions architecturales alternatives doit toutefois être arbitrée en fonction de la complexité de l’infrastructure logicielle, Pandas demeurant l’outil de référence absolu pour les environnements de recherche et de modélisation standards où les jeux de données s’intègrent confortablement dans la mémoire vive.
11. Diagnostic des anomalies, erreurs fréquentes et débogage
11.1 Résolution des exceptions KeyError et IndexError
L’implémentation de sélections de colonnes au sein de flux de travail automatisés s’accompagne inévitablement de défaillances opérationnelles qu’il convient de diagnostiquer avec méthode. L’exception la plus fréquemment rencontrée lors de l’extraction par liste ou via .loc est la fatidique KeyError. Cette erreur survient dès lors qu’au moins une étiquette déclarée dans la liste de sélection est introuvable au sein de l’index des colonnes du DataFrame.
Les origines profondes de cette anomalie sont bien souvent insidieuses :
- Espaces blancs résiduels : des caractères d’espacement situés au début ou à la fin d’une étiquette (par exemple ‘colonne_A ‘ au lieu de ‘colonne_A’) résultant d’une importation imparfaite d’un fichier CSV. Un nettoyage systématique préalable via df.columns = df.columns.str.strip() élimine préventivement cette source d’erreur.
- Casse typographique et caractères invisibles : des divergences entre majuscules et minuscules ou l’insertion accidentelle de caractères d’espacement insécables.
- Modifications structurelles de schémas amont : colonnes renommées ou supprimées lors d’une mise à jour de la base de données source.
Pour immuniser les scripts industriels contre les arrêts brutaux provoqués par une KeyError, une programmation défensive s’impose. L’analyste doit vérifier l’intersection ensembliste entre les colonnes cibles et les colonnes existantes au moyen de l’expression set(cols_cibles).issubset(df.columns). De manière alternative, l’interrogation par la méthode reindex() combinée à un argument de projection permet d’extraire les colonnes souhaitées tout en instanciant silencieusement des vecteurs de NaN pour les colonnes manquantes, sans jamais interrompre le fil d’exécution.
Quant à l’exception IndexError, elle émerge principalement lors de l’utilisation de l’accesseur .iloc lorsqu’un entier de positionnement excède la borne supérieure de la dimension horizontale (par exemple tenter d’accéder à l’index positionnel 10 dans un tableau ne comportant que 8 colonnes). La règle d’or pour prévenir ce dysfonctionnement réside dans la validation préalable de la propriété df.shape[1] avant d’exécuter tout découpage positionnel programmé.
11.2 Anomalies de conversion de type et types mixtes (object dtypes)
Une anomalie particulièrement déroutante pour les praticiens réside dans la défaillance silencieuse ou l’émission d’une TypeError lors du calcul de la moyenne sur des colonnes que l’on présumait purement arithmétiques. Cette pathologie découle presque invariablement de la présence d’un type d’extension générique object assigné par Pandas lors du parsing initial d’un fichier source.
Il suffit qu’une seule chaîne de caractères parasite réside au sein d’une colonne de plusieurs millions de nombres (comme la chaîne ‘N/A’, un tiret ‘-‘ matérialisant une valeur manquante dans un rapport financier, ou une coquille typographique) pour que Pandas renonce à inférer un type numérique strict et rétrograde l’intégralité de la colonne vers le type object. Si l’on tente d’exécuter une moyenne transversale sur un sous-ensemble incluant cette colonne, deux scénarios préjudiciables se présentent : soit le calcul s’interrompt avec une erreur d’incompatibilité de type, soit, dans des versions antérieures de Pandas, le système tente une concaténation textuelle chaotique le long de l’axe, produisant des résultats numériques désastreux.
Le diagnostic de cette pathologie repose sur l’inspection préalable des types via df[cols].dtypes. Pour assainir de manière définitive ces colonnes compromises, la méthode impérative consiste à contraindre la conversion arithmétique à l’aide de la fonction globale de Pandas : pd.to_numeric(). En spécifiant le paramètre errors=’coerce’, comme dans l’instruction df[col] = pd.to_numeric(df[col], errors=’coerce’), l’interpréteur transforme automatiquement toute chaîne textuelle parasite ou inconvertible en un marqueur standard NaN, restituant ainsi à la colonne son statut de nombre à virgule flottante exploitable par l’algorithme mean(axis=1).
12. Bonnes pratiques logicielles et intégration dans des pipelines de données
12.1 Encapsulation fonctionnelle et réutilisabilité du code
Au sein d’un écosystème de production logicielle ou d’un laboratoire de recherche industrielle, l’écriture de scripts monolithiques procéduraux calculant des moyennes au fil de l’eau est à proscrire impérativement. Les impératifs de maintenabilité, d’évolutivité et d’auditabilité exigent l’encapsulation de la logique d’agrégation transversale au sein de fonctions pures hautement réutilisables, dotées d’un typage statique rigoureux via le module standard typing de Python.
Une fonction de calcul de moyenne composite bien architecturée doit formellement documenter ses entrées et ses sorties. Elle reçoit en paramètre le DataFrame parent, la séquence textuelle identifiant les colonnes sélectionnées, ainsi que les options de gouvernance statistique (seuil de complétude minimale, tolérance aux valeurs manquantes, vecteur optionnel de pondérations). Sa signature typée garantit un contrat logiciel clair :
def calculer_moyenne_composite(data: pd.DataFrame, colonnes: list[str], seuil_completude: float = 0.8) -> pd.Series:
À l’intérieur de cette routine, l’implémentation déploie une séquence défensive standardisée : validation de l’existence des étiquettes au sein du schéma hôte, coercion des types numériques par assertion préventive, contrôle du taux d’observation minimal ligne par ligne, calcul vectorisé de la moyenne le long de l’axe horizontal, et enfin renvoi d’une Series isolée dont l’index est rigoureusement synchronisé avec le tableau source.
Cette approche fonctionnelle s’associe idéalement à des suites de tests unitaires automatisés orchestrés via le framework pytest. L’ingénieur peut alors concevoir une batterie d’assertions testant le comportement de la routine face à des cas limites (edge cases) : tableaux vides, colonnes ne contenant que des NaN, structures comportant des colonnes aux valeurs infinitésimales ou infinies, et vérification arithmétique de la précision du résultat calculé par rapport à une constante connue.
12.2 Enchaînement de méthodes (Method Chaining) et reproductibilité
Le paradigme moderne de manipulation de données dans Pandas privilégie la programmation déclarative et fluide par enchaînement de méthodes (method chaining). Ce style de conception architecturale repose sur l’utilisation intensive de la méthode assign(), laquelle permet de greffer de nouvelles colonnes calculées sur un DataFrame de manière pure et immuable, sans jamais modifier l’état interne de la structure originale par mutation destructive.
Dans un pipeline fluide articulé autour de method chaining, le calcul de la moyenne de colonnes sélectionnées s’exprime à l’aide d’une fonction anonyme lambda, assurant la continuité des opérations sans création de variables globales temporaires polluant l’espace de noms :
df_final = (
df_brut
.dropna(subset=[‘identifiant_sujet’])
.assign(moyenne_indicateurs=lambda x: x[[‘ind_1’, ‘ind_2’, ‘ind_3’]].mean(axis=1))
.query(‘moyenne_indicateurs > 2.5’)
.sort_values(by=’moyenne_indicateurs’, ascending=False)
)
Les bénéfices de cette architecture sont multiples. D’une part, l’élimination des états intermédiaires mutables prévient définitivement les effets de bord indésirables, rendant l’ensemble du flux de données déterministe et prédictible. D’autre part, la clarté topologique du script facilite grandement l’audit de code par les pairs et garantit la reproductibilité totale des expériences scientifiques, un prérequis devenu incontournable dans le cadre de la science ouverte et des déploiements d’intelligence artificielle en production.
En synthèse, maîtriser le calcul de la moyenne de colonnes sélectionnées dans Pandas transcende la simple mémorisation d’une directive de syntaxe. Cette opération mobilise une compréhension intégrée de la dimensionnalité matricielle, des mécanismes d’allocation mémoire, de la gestion probabiliste des valeurs manquantes, de la théorie des échelles de mesure et des préceptes du génie logiciel. En articulant judicieusement les accesseurs de pointe, les protocoles d’imputation rigoureux et les architectures de pipelines immuables, l’analyste garantit la scalabilité, la robustesse et la rectitude scientifique de l’ensemble de ses modélisations quantitatives.
Références
- Harris, C. R., Millman, K. J., van der Walt, S. J., Gommers, R., Virtanen, P., Cournapeau, D., … & Oliphant, T. E. (2020). Array programming with NumPy. Nature, 585(7825), 357-362. https://doi.org/10.1038/s41586-020-2649-2
- McKinney, W. (2010). Data Structures for Statistical Computing in Python. In S. van der Walt & J. Millman (Eds.), Proceedings of the 9th Python in Science Conference (pp. 56-61). https://doi.org/10.25080/Majora-92bf1924-00a
- McKinney, W. (2022). Python for Data Analysis: Data Wrangling with pandas, NumPy, and Jupyter (3rd ed.). O’Reilly Media.
- Pandas Development Team. (2024). pandas documentation: pandas.DataFrame.mean. PyData. https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.mean.html
- Rubin, D. B. (1976). Inference and missing data. Biometrika, 63(3), 581-592. https://doi.org/10.1093/biomet/63.3.581
- VanderPlas, J. (2016). Python Data Science Handbook: Essential Tools for Working with Data. O’Reilly Media.