L’analyse des phénomènes discrets constitue l’un des piliers fondamentaux de la statistique moderne, de l’économétrie, de l’apprentissage automatique et des sciences cognitives. Au cœur de cette modélisation stochastique se trouve la distribution binomiale, une loi de probabilité dont la rigueur formelle permet de quantifier les processus décisionnels binaires et les fréquences d’événements mutuellement exclusifs. De l’évaluation de l’efficacité d’un traitement expérimental au sein d’un essai clinique randomisé jusqu’à l’analyse des choix dans les protocoles de psychophysique, la maîtrise de cette distribution est indispensable pour tout chercheur ou praticien de la science des données. Le langage Python, fort de son écosystème de calcul scientifique unifié autour de bibliothèques telles que NumPy, SciPy, pandas et Statsmodels, offre un environnement computationnel robuste et optimisé pour manipuler, simuler et estimer ces modèles stochastiques.
Le traitement informatique des distributions discrètes requiert néanmoins une compréhension approfondie qui dépasse la simple invocation de fonctions logicielles. L’expérimentateur doit appréhender avec précision les contraintes de stabilité numérique, la gestion de la précision en virgule flottante, les risques d’annulation catastrophique lors du calcul de probabilités résiduelles extrêmes, ainsi que les hypothèses distributionnelles sous-jacentes. En effet, la transition entre la théorie probabiliste axiomatique et son implémentation dans une architecture matérielle à précision finie soulève des défis d’ingénierie logicielle non négligeables, notamment lorsqu’il s’agit de générer des millions de tirages pseudo-aléatoires ou d’estimer des intervalles de confiance exacts non asymptotiques.
Ce guide exhaustif propose une exploration approfondie de la distribution binomiale en environnement Python, alliant rigueur mathématique, implémentations algorithmiques de référence et cas d’usage avancés issus des neurosciences et des sciences comportementales. À travers une progression méthodique articulée autour de douze sections analytiques, nous aborderons les fondements théoriques, l’échantillonnage vectorisé à haute performance, le calcul analytique exact des fonctions de masse et de répartition, l’inférence fréquentiste et bayésienne, ainsi que la modélisation multivariée via les modèles linéaires généralisés. Cette démarche permettra de doter le lecteur des compétences théoriques et pratiques nécessaires pour concevoir des protocoles d’analyse stochastique reproductibles, efficients et conformes aux plus hauts standards de la recherche quantitative contemporaine.
- 1. Fondements théoriques et mathématiques de la loi binomiale
- 2. Configuration de l’environnement Python et outillage scientifique
- 3. Échantillonnage stochastique avec le module NumPy
- 4. Calcul des probabilités exactes avec SciPy (PMF)
- 5. Calcul des probabilités cumulées avec SciPy (CDF et SF)
- 6. Calcul des quantiles et de la fonction quantile inverse (PPF)
- 7. Visualisation graphique avancée des distributions binomiales
- 8. Inférence statistique et test binomial exact en Python
- 9. Approximations asymptotiques : loi normale et loi de Poisson
- 10. Inférence bayésienne et modèle conjugué Bêta-Binomial
- 11. Modélisation par régression logistique et processus binomiaux
- 12. Études de cas appliquées aux sciences du comportement et neurosciences cognitives
- Références
1. Fondements théoriques et mathématiques de la loi binomiale
1.1 Définition axiomatique et processus de Bernoulli
La formalisation mathématique de la loi binomiale repose sur le concept fondamental d’épreuve de Bernoulli, formulé initialement par le mathématicien suisse Jacques Bernoulli dans son ouvrage posthume Ars Conjectandi (1713). Une épreuve de Bernoulli est une expérience aléatoire élémentaire ne comportant que deux issues possibles et mutuellement exclusives, conventionnellement désignées sous les termes de « succès » (noté 1) et d’« échec » (noté 0). L’espace fondamental associé à une telle expérience est défini par l’ensemble discret Ω = {0, 1}. On lui associe une mesure de probabilité P telle que P({1}) = p et P({0}) = 1 – p = q, avec la contrainte stricte que le paramètre de probabilité appartienne à l’intervalle fermé [0, 1].
Lorsque l’on étend ce cadre conceptuel à une succession de n épreuves, la loi binomiale émerge naturellement comme la distribution de la somme de ces variables aléatoires sous des conditions très strictes d’indépendance et d’homogénéité. Soit une suite (Y1, Y2, …, Yn) de variables aléatoires indépendantes et identiquement distribuées (i.i.d.) selon une loi de Bernoulli de paramètre commun p. La variable aléatoire discrète X, définie par la sommation :
X = ∑i=1n Yi
mesure le nombre total de succès observés au cours de ces n réalisations. L’espace d’état ou support de la variable X est par conséquent l’ensemble discret des entiers naturels SX = {0, 1, 2, …, n}.
La validité de cette modélisation requiert deux conditions axiomatiques invariables : la stationnarité du paramètre de succès p tout au long de la séquence expérimentale, et l’indépendance stochastique mutuelle de l’ensemble des épreuves. L’indépendance implique formellement que pour toute sous-suite d’indices, la probabilité conjointe factorise en produit des probabilités marginales. Si l’un des tirages venait à modifier la composition de l’urne d’échantillonnage sans remise, la probabilité varierait à chaque itération, conduisant non pas à une loi binomiale, mais à une loi hypergéométrique. Il convient également de distinguer formellement les distributions discrètes des distributions continues : alors que les variables continues possèdent une densité de probabilité nulle en tout point singulier, les variables discrètes comme la loi binomiale concentrent leur masse sur un ensemble dénombrable de points isolés, conférant à chaque réalisation un poids probabiliste univoque et non nul.
1.2 Formulation analytique de la fonction de masse de probabilité
La fonction de masse de probabilité (désignée sous l’acronyme PMF pour Probability Mass Function) associe à chaque entier k appartenant au support {0, 1, …, n} la probabilité exacte d’observer précisément k succès parmi les n essais réalisés. L’établissement de cette formule procède d’une analyse combinatoire rigoureuse. Considérons une séquence particulière de résultats contenant k succès et (n – k) échecs dans un ordre prédéterminé, par exemple la séquence où les k premiers essais sont des succès suivis de (n – k) échecs. En vertu du postulat d’indépendance mutuelle des épreuves, la probabilité d’occurrence conjointe d’une telle configuration s’écrit comme le produit des probabilités individuelles :
P(Séquence spécifique) = p × p × … × p × (1 – p) × … × (1 – p) = pk(1 – p)n – k
Cependant, l’ordre d’apparition des succès et des échecs au sein de la séquence globale est indifférent à l’observateur qui ne s’intéresse qu’au cardinal total de succès. Il est donc nécessaire de dénombrer l’ensemble des permutations distinctes permettant d’ordonner ces k succès parmi les n positions disponibles. Ce dénombrement correspond précisément au coefficient binomial, noté C(n, k) ou plus communément via la notation matricielle :
&Binomial(n, k); = n! / (k!(n – k)!)
Par application directe du principe d’additivité des probabilités pour des événements incompatibles, la fonction de masse s’énonce selon la formulation analytique canonique :
P(X = k) = &Binomial(n, k); pk(1 – p)n – k, ∀ k ∈ {0, 1, …, n}
Pour que cette fonction constitue une mesure de probabilité légitime sur l’espace d’états, la condition de normalisation unitaire doit être impérativement satisfaite. La démonstration de cette propriété découle directement de la formule du binôme de Newton :
∑k=0n P(X = k) = ∑k=0n &Binomial(n, k); pk(1 – p)n – k = (p + (1 – p))n = 1n = 1
Cette sommation unitaire garantit la cohérence probabiliste de la distribution. Toute implémentation informatique destinée à simuler cette fonction doit préserver cette propriété structurelle, sous peine d’induire des dérives cumulatives lors des analyses statistiques à grande échelle.
1.3 Propriétés distributionnelles et moments statistiques
Les moments statistiques d’une variable aléatoire capturent la forme, la tendance centrale et la dispersion de sa distribution. L’espérance mathématique, ou moment d’ordre un, s’obtient élégamment en tirant parti de la linéarité de l’opérateur d’espérance appliqué à la décomposition de Bernoulli X = ∑ Yi. Puisque chaque indicatrice de succès Yi possède une espérance E[Yi] = 1 × p + 0 × (1 – p) = p, l’espérance globale de la variable binomiale s’écrit sans ambiguïté :
E[X] = E[∑i=1n Yi] = ∑i=1n E[Yi] = np
La variance, moment centré d’ordre deux, quantifie l’amplitude des fluctuations stochastiques autour de la moyenne théorique. Sous l’hypothèse d’indépendance mutuelle des variables Yi, les covariances croisées Cov(Yi, Yj) s’annulent identiquement pour i ≠ j. La variance de la somme est alors strictement égale à la somme des variances individuelles :
Var(X) = ∑i=1n Var(Yi) = n × (E[Yi2] – (E[Yi])2) = n(p – p2) = np(1 – p)
L’écart-type est par définition σ = √(np(1 – p)). L’examen analytique de cette expression révèle une propriété remarquable : la fonction quadratique f(p) = p(1 – p) admet sa valeur maximale absolue en p = 0,5, où elle atteint 0,25. Ainsi, à taille d’échantillon n fixée, l’incertitude stochastique et la dispersion des mesures sont maximales lorsque le système présente une équiprobabilité parfaite entre le succès et l’échec.
Les moments d’ordre supérieur caractérisent les déformations morphologiques de la distribution. Le coefficient d’asymétrie (ou skewness de Fisher), noté γ1, mesure le manque de symétrie de la fonction de masse autour de son espérance :
γ1 = (1 – 2p) / √(np(1 – p))
On constate immédiatement que si p = 0,5, le coefficient s’annule identiquement (γ1 = 0), traduisant une symétrie axiale parfaite de la fonction de masse. Lorsque p < 0,5, γ1 > 0, induisant un étirement de la queue de distribution vers la droite (valeurs élevées). Inversement, lorsque p > 0,5, γ1 < 0, la distribution présente une asymétrie négative avec un étalement vers la gauche. Enfin, le coefficient d’aplatissement (ou kurtosis excessif de Fisher) γ2 mesure la propension de la loi à générer des valeurs extrêmes comparativement à une loi normale :
γ2 = (1 – 6p(1 – p)) / (np(1 – p))
Lorsque le paramètre n tend vers l’infini, les coefficients γ1 et γ2 convergent asymptotiquement vers 0, illustrant concrètement l’action régulatrice du théorème central limite sur la topologie de la distribution.
2. Configuration de l’environnement Python et outillage scientifique
2.1 Écosystème informatique pour le calcul probabiliste
L’implémentation de modèles probabilistes en Python repose sur une pile logicielle rigoureusement architecturée, dont le socle computationnel est constitué par NumPy. NumPy introduit une structure de données hautement optimisée en langage C, le tableau multidimensionnel (ndarray), permettant de contourner les lenteurs intrinsèques aux listes chaînées et au typage dynamique de Python standard. L’exécution d’opérations vectorisées au niveau du compilateur C autorise le traitement simultané de plusieurs dizaines de millions d’éléments probabilistes avec des gains de performance de plusieurs ordres de grandeur par rapport aux boucles natives.
Au-dessus de cette infrastructure de bas niveau, la bibliothèque SciPy, et plus particulièrement son sous-module scipy.stats, fournit les définitions analytiques formelles de centaines de variables aléatoires. Contrairement à NumPy, qui se concentre sur l’échantillonnage rapide et les opérations sur tenseurs, scipy.stats expose des classes d’objets encapsulant les fonctions mathématiques pures : fonctions de masse de probabilité (PMF), fonctions de répartition cumulée (CDF), fonctions de survie (SF) et fonctions de point de pourcentage (PPF ou quantiles inverses). Cette distinction fonctionnelle entre génération pseudo-aléatoire (NumPy) et calcul infinitésimal exact (SciPy) constitue un standard architectural en science des données.
Pour la restitution et l’inspection empirique des données discrètes, l’association de matplotlib.pyplot et de seaborn s’avère incontournable. Ces modules permettent de transcrire les matrices d’états stochastiques en figures vectorielles de haute fidélité. Sur le plan matériel, les contraintes liées à la norme IEEE 754 régissant la représentation des nombres flottants en double précision (64 bits) imposent une vigilance particulière. En Python standard, les flottants possèdent 53 bits de mantisse, offrant une précision relative d’environ 15 à 17 chiffres décimaux significatifs. Lors du calcul de probabilités combinatoires impliquant de très grands factoriels, le risque de débordement arithmétique (overflow) ou de sous-dépassement (underflow) nécessite l’emploi d’algorithmes stables formulés dans l’espace logarithmique, un mécanisme que gère SciPy en interne de façon transparente.
2.2 Gestion de la reproductibilité et générateurs stochastiques
L’intégrité de la recherche scientifique quantitative dépend de la reproductibilité exacte des protocoles de simulation stochastique. Historiquement, l’écosystème NumPy reposait sur un état aléatoire global accessible via l’instruction numpy.random.seed(), basée sur l’algorithme Mersenne Twister (MT19937). Bien que populaire, cette approche présentait des failles structurelles : manque de sécurité lors de l’exécution concurrente (multithreading), contamination de l’état aléatoire global entre différents modules logiciels indépendants, et propriétés statistiques sous-optimales pour les flux stochastiques à très haute dimension.
Depuis la publication de la version 1.17 de NumPy, l’API aléatoire a été entièrement réarchitecturée autour du concept de Generator instancié par la fonction d’usine numpy.random.default_rng(). Cette architecture moderne substitue le moteur PCG64 (Permuted Congruential Generator) au vieillissant Mersenne Twister. Le générateur PCG64 garantit une période considérablement étendue, une dispersion spatiale supérieure des vecteurs pseudo-aléatoires et un partitionnement d’état déterministe pour le calcul distribué :
import numpy as np
# Initialisation d'un générateur isolé et déterministe via une graine entière
seed_experimentale = 42
rng = np.random.default_rng(seed=seed_experimentale)
# L'objet rng est désormais l'unique point d'entrée pour les tirages stochastiques
tirage_controle = rng.binomial(n=10, p=0.5, size=5)
print("Échantillons reproductibles :", tirage_controle)
Pour assurer la traçabilité absolue d’un protocole de recherche, il est recommandé de sauvegarder l’état interne complet du générateur (accessible via rng.bit_generator.state) conjointement avec les métadonnées expérimentales. Cette sérialisation permet de reprendre exactement une simulation interrompue à un état stochastique précis, garantissant une rigueur méthodologique irréprochable.
2.3 Structures de données pour l’analyse stochastique
La volumétrie des simulations computationnelles modernes requiert une sélection rigoureuse des structures de données en mémoire. Un tirage de Bernoulli ou une réalisation binomiale produit des entiers naturels. Par défaut, NumPy alloue souvent des entiers signés 64 bits (int64), ce qui représente une allocation mémoire de 8 octets par élément scalaire. Dans le cadre d’une simulation massive comportant 108 épreuves, cette allocation standard mobilise environ 800 mégaoctets de mémoire vive.
Or, le support d’une loi binomiale pour n ≤ 255 peut être intégralement encodé sur des entiers non signés 8 bits (uint8), requérant un unique octet par réalisation. En adaptant les types de données (dtypes) lors de la génération de grandes matrices de cohortes expérimentales, le chercheur divise l’empreinte mémoire par huit, tout en accélérant les débits de transfert au sein de la hiérarchie des mémoires caches du processeur (L1, L2, L3) :
import pandas as pd
# Allocation optimisée d'un tableau volumineux
taille_simulation = 10_000_000
tirages_bruts = rng.binomial(n=20, p=0.3, size=taille_simulation).astype(np.uint8)
# Intégration dans une structure de données tabulaire pandas
df_essais = pd.DataFrame({
'succes_observes': tirages_bruts
})
# Vérification de l'empreinte mémoire optimisée
memoire_mo = df_essais.memory_usage(deep=True).sum() / (1024 ** 2)
print(f"Empreinte mémoire totale : {memoire_mo:.2f} Mo")
La conversion sélective de ces tableaux NumPy vers des objets pandas.DataFrame facilite les opérations d’agrégation groupée, le filtrage conditionnel, l’imputation de covariables expérimentales et la préparation des données pour les régressions économétriques ou psychométriques ultérieures.
3. Échantillonnage stochastique avec le module NumPy
3.1 Syntaxe fondamentale de la méthode random.binomial
L’échantillonnage de variables aléatoires binomiales s’effectue au moyen de la méthode rng.binomial() de l’objet générateur de NumPy. Cette méthode repose sur des algorithmes d’inversion directe et de transformation par rejet optimisés au niveau assembleur, capables d’adapter dynamiquement leur stratégie computationnelle selon l’amplitude des paramètres n et p. La signature fonctionnelle de cette méthode prend la forme générale suivante :
Generator.binomial(n, p, size=None)
Les trois arguments d’appel gouvernent intégralement le comportement stochastique du générateur :
n(entier ou tableau d’entiers) : représente le nombre d’épreuves de Bernoulli indépendantes composant chaque tirage binomial. Ce paramètre doit impérativement être supérieur ou égal à zéro.p(flottant ou tableau de flottants) : correspond à la probabilité de succès associée à chaque épreuve individuelle, avec la contrainte stricte que 0 ≤ p ≤ 1.size(entier ou tuple d’entiers, optionnel) : détermine la forme dimensionnelle (shape) du tenseur de sortie. Lorsquesize=None, la méthode renvoie un scalaire unique extrait de la distribution. Si un tuple est spécifié (ex.(1000, 5)), NumPy synthétise une matrice multidimensionnelle conforme à ces dimensions.
Sur le plan sémantique, la valeur numérique retournée par la méthode représente le comptage effectif des succès réalisés au cours des n épreuves. Considérons l’implémentation suivante illustrant la génération scalaire et vectorielle élémentaire :
# Génération d'un scalaire isolé (résultat d'une expérience unique de 20 essais)
score_individuel = rng.binomial(n=20, p=0.4)
print("Score scalaire :", score_individuel)
# Génération vectorielle d'une cohorte de 8 participants indépendants
scores_cohorte = rng.binomial(n=20, p=0.4, size=8)
print("Scores vectoriels de la cohorte :", scores_cohorte)
3.2 Génération de matrices d’expériences simulées
L’évaluation des propriétés de grands systèmes expérimentaux exige fréquemment la simulation simultanée de multiples cohortes d’individus soumises à des conditions expérimentales hétérogènes. NumPy excelle dans cet exercice grâce à la vectorisation implicite : il n’est nullement nécessaire de recourir à des boucles itératives pour faire varier les paramètres d’un sujet à l’autre. Les arguments n et p peuvent eux-mêmes être des tableaux dont la dimension s’accorde, selon les règles de diffusion (broadcasting) de NumPy, avec le paramètre size.
Supposons que nous souhaitions simuler une matrice expérimentale comportant 500 groupes de test, chaque groupe comprenant 1 000 participants réalisant une tâche d’inhibition cognitive de 50 essais, avec un gradient de difficulté modélisé par une probabilité de succès fluctuant entre 0,2 et 0,8 :
n_groupes = 500
n_participants = 1000
essais_par_sujet = 50
# Vecteur des probabilités de succès variant linéairement entre les groupes
probabilites_groupes = np.linspace(0.2, 0.8, n_groupes)[:, np.newaxis]
# Génération matricielle en une seule passe sans aucune boucle Python
# Dimensions résultantes : (500, 1000)
matrice_experiences = rng.binomial(n=essais_par_sujet, p=probabilites_groupes, size=(n_groupes, n_participants))
# Indexation booléenne pour identifier les cohortes hautement performantes
# Condition : moyenne du groupe strictement supérieure à 35 succès
moyennes_groupes = np.mean(matrice_experiences, axis=1)
groupes_d_elite = matrice_experiences[moyennes_groupes > 35, :]
print("Dimensions de la matrice globale :", matrice_experiences.shape)
print("Nombre de groupes qualifiés d'élite :", groupes_d_elite.shape[0])
L’évaluation des temps de calcul démontre que l’approche vectorisée matricielle surpasse les boucles conventionnelles de type for imbriquées d’un facteur excédant généralement 150x, illustrant l’efficacité critique du moteur interne de NumPy pour la recherche computationnelle intensive.
3.3 Analyse empirique des données d’échantillonnage
Une fois les tenseurs d’échantillons synthétisés, l’analyse descriptive empirique permet de vérifier la validité expérimentale et de confronter les mesures observées aux valeurs théoriques prédites par l’analyse combinatoire. En vertu de la loi forte des grands nombres formulée par Émile Borel, la moyenne arithmétique empirique d’une séquence de variables aléatoires i.i.d. converge presque sûrement vers son espérance mathématique E[X] = np lorsque la taille de l’échantillon N tend vers l’infini :
limN → ∞ (1 / N) ∑j=1N Xj = np
De même, la variance échantillonnale non biaisée converge vers la variance paramétrique théorique np(1 – p). Il est possible de mettre en œuvre un script de suivi dynamique documentant cette convergence asymptotique à travers un spectre d’échantillonnage logarithmique allant de 10 à 1 000 000 d’itérations :
param_n = 40
param_p = 0.35
esperance_theorique = param_n * param_p
variance_theorique = param_n * param_p * (1 - param_p)
tailles_echantillon = [10, 100, 1_000, 10_000, 100_000, 1_000_000]
print(f"Théorique -> Espérance : {esperance_theorique:.4f} | Variance : {variance_theorique:.4f}n")
for N in tailles_echantillon:
tirages = rng.binomial(n=param_n, p=param_p, size=N)
moyenne_empirique = np.mean(tirages)
# ddof=1 pour l'estimateur sans biais de la variance d'échantillon
variance_empirique = np.var(tirages, ddof=1)
erreur_relative_moyenne = abs(moyenne_empirique - esperance_theorique) / esperance_theorique * 100
print(f"N = {N:9d} | Moyenne : {moyenne_empirique:.4f} (Err: {erreur_relative_moyenne:6.3f}%) | Variance : {variance_empirique:.4f}")
Les sorties numériques confirment la décrue monotone de l’erreur relative à mesure que la puissance statistique augmente, fournissant une validation empirique robuste des mécanismes d’échantillonnage de NumPy.
4. Calcul des probabilités exactes avec SciPy (PMF)
4.1 Utilisation de scipy.stats.binom.pmf pour un événement ponctuel
Alors que NumPy est dédié à la génération d’échantillons stochastiques aléatoires, le sous-module scipy.stats permet d’évaluer directement les valeurs exactes des équations probabilistes. La méthode scipy.stats.binom.pmf(k, n, p) calcule la probabilité ponctuelle d’observer exactement k succès au cours de n essais de Bernoulli dotés d’une probabilité de succès individuelle p. Sa signature analytique résout directement l’expression combinatoire C(n, k) pk (1 – p)n – k sans nécessiter d’approximation stochastique.
L’évaluation directe de cette formule via les factoriels classiques (par exemple avec la fonction math.comb ou math.factorial) présente un risque structurel d’explosion combinatoire. Dès lors que n > 170, le calcul de n! dépasse la capacité maximale d’un flottant double précision (environ 1,79 × 10308), générant une exception d’interruption arithmétique (OverflowError). scipy.stats contourne élégamment cet écueil en réalisant les calculs dans l’espace logarithmique via la fonction de log-masse de probabilité (logpmf), s’appuyant sur la fonction gamma spéciale :
ln P(X = k) = ln Γ(n + 1) – ln Γ(k + 1) – ln Γ(n – k + 1) + k ln p + (n – k) ln(1 – p)
L’exponentielle du résultat est ensuite calculée avec une précision absolue, garantissant une robustesse numérique exceptionnelle même pour des valeurs de n atteignant plusieurs dizaines de milliers :
from scipy import stats
import math
n_essais = 250
k_succes = 115
proba_succes = 0.45
# Évaluation standard via SciPy
proba_exacte = stats.binom.pmf(k=k_succes, n=n_essais, p=proba_succes)
log_proba = stats.binom.logpmf(k=k_succes, n=n_essais, p=proba_succes)
print(f"Probabilité exacte P(X = {k_succes}) : {proba_exacte:.8e}")
print(f"Log-probabilité correspondante : {log_proba:.8f}")
# Tentative manuelle avec math.comb (susceptible de déborder pour de très grands nombres)
combinaisons = math.comb(n_essais, k_succes)
proba_manuelle = combinaisons * (proba_succes ** k_succes) * ((1 - proba_succes) ** (n_essais - k_succes))
print(f"Cohérence math.comb vs SciPy : {math.isclose(proba_exacte, proba_manuelle)}")
4.2 Vectorisation du calcul sur un continuum d’états de succès
L’architecture de scipy.stats.binom.pmf supporte nativement la diffusion de tableaux pour l’ensemble de ses arguments formels. En transmettant un vecteur complet d’entiers à l’argument k, la fonction renvoie le spectre distributionnel intégral de la variable aléatoire en une seule opération vectorisée. Cette fonctionnalité permet d’auditer l’ensemble du domaine discret et de valider les axiomes probabilistes sur l’intégralité de l’espace d’états :
n_total = 30
p_individuel = 0.25
# Support complet allant de 0 à n succès
support_k = np.arange(0, n_total + 1)
# Évaluation vectorisée de la fonction de masse
spectre_probabilites = stats.binom.pmf(k=support_k, n=n_total, p=p_individuel)
# Validation empirique de l'axiome de normalisation unitaire
somme_totale = np.sum(spectre_probabilites)
print(f"Somme de la mesure sur l'espace d'états : {somme_totale:.16f}")
print("Axiome de normalisation vérifié :", np.isclose(somme_totale, 1.0))
# Structuration dans une table pandas pour analyse analytique
tableau_pmf = pd.DataFrame({
'k_Succes': support_k,
'Probabilite': spectre_probabilites
})
print(tableau_pmf.head(6))
Cette approche élimine tout risque d’erreur d’indice inhérent à l’écriture manuelle d’itérations, tout en assurant une vitesse d’exécution optimale pour la génération de tables actuarielles ou statistiques exhaustives.
4.3 Modélisation d’une tâche de reconnaissance mnésique
Considérons une application concrète issue de la neuropsychologie expérimentale : le paradigme de reconnaissance visuelle « ancien / nouveau » (Old/New recognition task). Un patient amnésique se voit présenter une série séquentielle de 40 images complexes. Lors de la phase de test ultérieure, 40 paires d’images sont soumises au sujet, chaque paire contenant un item précédemment encodé et un leurre inédit. La tâche consiste à désigner l’item cible. Il s’agit d’une tâche de choix forcé à deux alternatives (2AFC, pour Two-Alternative Forced Choice).
Sous l’hypothèse nulle (H0) stipulant que les traces mnésiques du patient sont totalement inopérantes et que son comportement relève de la simple devinette stochastique, la probabilité de succès à chaque essai est rigoureusement égale à p = 0,5. Le nombre total d’essais est n = 40. Supposons que le patient obtienne un score de 27 détections correctes. Quelle est la probabilité exacte d’observer précisément cette performance sous le modèle du hasard pur ?
n_items = 40
p_hasard = 0.5
performance_observee = 27
# Calcul de la probabilité ponctuelle sous H0
p_exacte_observation = stats.binom.pmf(k=performance_observee, n=n_items, p=p_hasard)
print(f"Probabilité d'observer exactement {performance_observee} succès par simple hasard : {p_exacte_observation:.5f}")
Bien que cette probabilité ponctuelle soit intrinsèquement faible (environ 0,019), il convient d’avertir l’expérimentateur quant à l’erreur conceptuelle classique consistant à confondre la probabilité ponctuelle P(X = k) avec la significativité statistique. Pour juger du caractère exceptionnel de cette performance mnésique, il est théoriquement impératif de sommer les probabilités de tous les événements au moins aussi extrêmes que celui observé, ce qui introduit naturellement la nécessité du calcul des probabilités cumulées.
5. Calcul des probabilités cumulées avec SciPy (CDF et SF)
5.1 Évaluation de la queue inférieure avec binom.cdf
La fonction de répartition cumulative (désignée sous l’acronyme CDF pour Cumulative Distribution Function) associe à tout seuil réel k la probabilité qu’une variable aléatoire X prenne une valeur inférieure ou égale à ce seuil. Dans le cadre discret de la distribution binomiale, elle s’énonce formellement comme la somme discrète finie :
F(k) = P(X ≤ k) = ∑i=0⌊k⌋ &Binomial(n, i); pi(1 – p)n – i
où ⌊k⌋ désigne la partie entière de k. L’évaluation de cette probabilité cumulée s’effectue sous SciPy à l’aide de la méthode scipy.stats.binom.cdf(k, n, p). Cette fonction ne réalise pas une sommation naïve des valeurs de la PMF, mais s’appuie sur la relation mathématique exacte liant la fonction de répartition de la loi binomiale à la fonction bêta incomplète régularisée Ix(a, b) :
P(X ≤ k) = I1 – p(n – k, k + 1)
Cette formulation analytique garantit une convergence numérique instantanée et supprime l’accumulation d’erreurs d’arrondi qui altère fréquemment les boucles sommatoires itératives.
Dans le domaine de l’évaluation psychométrique ou médicale, la CDF permet d’identifier avec précision les seuils d’échec ou de déficience cognitive. Supposons qu’un protocole d’aptitude standardisé comporte 60 items administrés à des sujets neurotypiques (avec p = 0,75 de taux de réussite moyen). On cherche à évaluer la probabilité qu’un sujet réponde correctement à 32 questions ou moins, signalant un potentiel déficit attentionnel :
n_batterie = 60
p_normatif = 0.75
seuil_deficience = 32
# Évaluation via la CDF de SciPy
probabilite_queue_inferieure = stats.binom.cdf(k=seuil_deficience, n=n_batterie, p=p_normatif)
print(f"P(X <= {seuil_deficience}) : {probabilite_queue_inferieure:.6e}")
Le résultat obtenu, inférieur à 10-4, confirme le caractère hautement atypique d’un tel score au sein de la population normative.
5.2 Modélisation de la queue supérieure via binom.sf
L’évaluation des scores exceptionnellement élevés ou des temps de survie stochastiques requiert l’estimation de la probabilité de queue supérieure, c’est-à-dire l’événement complémentaire P(X > k). En analyse mathématique élémentaire, cette grandeur est définie par l’identité triviale P(X > k) = 1 – P(X ≤ k). Néanmoins, sur le plan computationnel, l’application directe de la formulation 1.0 - stats.binom.cdf(k, n, p) constitue une erreur méthodologique majeure dès lors que P(X ≤ k) est très proche de 1.
En arithmétique flottante standard IEEE 754, la soustraction de deux nombres extrêmement proches induit un phénomène d’annulation catastrophique (catastrophic cancellation) : les bits de précision de la mantisse sont éliminés, aboutissant à une troncature prématurée à zéro dès que la probabilité complémentaire descend sous la précision machine (typiquement ~10-16). Pour pallier cette dégénérescence numérique, SciPy propose la fonction de survie dédiée : scipy.stats.binom.sf(k, n, p) (pour Survival Function). La méthode binom.sf calcule directement la queue supérieure en exploitant la complémentarité de la fonction bêta incomplète :
P(X > k) = Ip(k + 1, n – k)
n_essais_cliniques = 1000
p_base = 0.5
seuil_critique = 620
# Approche naïve présentant un risque d'instabilité numérique
approche_naive = 1.0 - stats.binom.cdf(seuil_critique, n_essais_cliniques, p_base)
# Approche robuste via la fonction de survie
approche_sf = stats.binom.sf(seuil_critique, n_essais_cliniques, p_base)
print(f"Formulation naïve (1 - CDF) : {approche_naive:.18e}")
print(f"Fonction de survie (SF) : {approche_sf:.18e}")
print(f"Différence relative : {abs(approche_naive - approche_sf) / approche_sf:.4e}")
L’écart de précision devient encore plus flagrant lors de l’étude d’événements extrêmes, où la méthode naïve s’effondre systématiquement à 0.0 tandis que binom.sf continue de fournir des estimations précises jusqu’à des ordres de grandeur de 10-300.
5.3 Résolution de probabilités d’intervalles stochastiques
L’évaluation de la probabilité qu’une variable aléatoire binomiale X s’inscrive au sein d’un intervalle arbitraire [a, b] constitue une nécessité opérationnelle fréquente. La formalisation rigoureuse de ces probabilités d’intervalle requiert une attention minutieuse aux bornes strictes et larges, l’espace d’état étant discret :
- Intervalle fermé P(a ≤ X ≤ b) = P(X ≤ b) – P(X ≤ a – 1)
- Intervalle semi-ouvert à gauche P(a < X ≤ b) = P(X ≤ b) – P(X ≤ a)
- Intervalle ouvert strict P(a < X < b) = P(X ≤ b – 1) – P(X ≤ a)
Afin d’encapsuler ces règles combinatoires au sein d’un composant logiciel réutilisable, il est judicieux d’implémenter une fonction modulaire gérant avec précision les conditions aux limites et vérifiant l’ordonnancement mathématique des arguments d’entrée :
def evaluer_intervalle_binomial(a: int, b: int, n: int, p: float, mode: str = 'ferme') -> float:
"""
Calcule la probabilité exacte qu'une variable X ~ B(n, p) appartienne à un intervalle spécifié.
Modes acceptés : 'ferme' [a, b], 'ouvert' (a, b), 'semi_gauche' (a, b], 'semi_droite' [a, b)
"""
if not (0 <= a <= n and 0 <= b b:
raise ValueError("La borne inférieure a ne peut excéder la borne supérieure b.")
if mode == 'ferme':
# P(a <= X 0 else 0.0
elif mode == 'semi_gauche':
# P(a < X <= b) = CDF(b) - CDF(a)
borne_sup = stats.binom.cdf(b, n, p)
borne_inf = stats.binom.cdf(a, n, p)
elif mode == 'ouvert':
# P(a < X 0 else 0.0
borne_inf = stats.binom.cdf(a, n, p)
elif mode == 'semi_droite':
# P(a <= X 0 else 0.0
borne_inf = stats.binom.cdf(a - 1, n, p) if a > 0 else 0.0
else:
raise ValueError("Mode d'intervalle non reconnu.")
return float(np.clip(borne_sup - borne_inf, 0.0, 1.0))
# Exemple d'application : cohortes comportementales de taille n = 100 avec p = 0.5
# Quelle est la probabilité d'obtenir une performance intermédiaire comprise entre 45 et 55 succès inclus ?
p_intervalle = evaluer_intervalle_binomial(a=45, b=55, n=100, p=0.5, mode='ferme')
print(f"P(45 <= X <= 55) : {p_intervalle:.5f}")
6. Calcul des quantiles et de la fonction quantile inverse (PPF)
6.1 Définition théorique de la fonction de point de pourcentage (PPF)
Alors que la fonction de répartition cumulative calcule une probabilité à partir d’une valeur de réalisation k, les protocoles expérimentaux exigent régulièrement la démarche inverse : déterminer le score seuil k correspondant à un centile de performance ou à un niveau de risque d’erreur α prédéterminé. Pour une variable aléatoire continue, cette opération correspond à l’inversion analytique pure de la fonction de répartition continue x = F-1(q).
Cependant, dans le cas d’une distribution discrète, la fonction de répartition se présente sous la forme d’une fonction en escalier, présentant des discontinuités de saut à chaque valeur entière du support. Par conséquent, la fonction de répartition cumulative n’est pas strictement bijective, et son inverse exacte n’existe pas au sens usuel. On définit alors l’inverse généralisé de la fonction de répartition, traditionnellement désigné sous l’appellation de fonction quantile ou fonction de point de pourcentage (PPF pour Percent Point Function), par la borne inférieure :
Q(q) = inf { k ∈ {0, 1, …, n} : P(X ≤ k) ≥ q }, ∀ q ∈ [0, 1]
Cette formulation mathématique stipule que le quantile d’ordre q est le plus petit entier naturel k tel que la probabilité cumulée atteigne ou dépasse le seuil probabiliste q. Cette relation de dualité fondamentale implique que la fonction quantile d’une loi discrète est continue à droite et croissante par paliers.
6.2 Implémentation technique de scipy.stats.binom.ppf
L’environnement SciPy expose cette inversion généralisée via la méthode scipy.stats.binom.ppf(q, n, p). Cette méthode prend en charge aussi bien des valeurs scalaires de quantiles que des tenseurs de percentiles. Lorsque l’utilisateur soumet un percentile q = 0, la fonction retourne naturellement 0 ; à l’extrême opposé, lorsque q = 1, elle renvoie la borne maximale théorique n.
Il est aisé de décomposer la structure quantile d’une distribution binomiale standard (par exemple n = 100, p = 0,3) pour en extraire les principaux indicateurs de dispersion non paramétrique : le premier quartile (q = 0,25), la médiane théorique (q = 0,50) et le troisième quartile (q = 0,75) :
taille_echantillon_n = 100
param_proba_p = 0.3
# Extraction des quartiles théoriques
quantiles_cibles = np.array([0.25, 0.50, 0.75])
seuils_k = stats.binom.ppf(quantiles_cibles, n=taille_echantillon_n, p=param_proba_p)
print("Quartiles théoriques correspondants [Q1, Q2 (Médiane), Q3] :", seuils_k)
# Démonstration de la propriété de seuil infimum
k_mediane = int(seuils_k[1])
cdf_k_moins_1 = stats.binom.cdf(k_mediane - 1, n=taille_echantillon_n, p=param_proba_p)
cdf_k = stats.binom.cdf(k_mediane, n=taille_echantillon_n, p=param_proba_p)
print(f"P(X <= {k_mediane - 1}) = {cdf_k_moins_1:.4f} (< 0.50)")
print(f"P(X = 0.50)")
Cette vérification confirme sans équivoque la logique de seuillage discret : l’entier sélectionné par binom.ppf est l’unique entier où la masse cumulée franchit le seuil fixé.
6.3 Application psychométrique : calibrage de seuils de décision
Dans la conception de batteries psychométriques ou de tests de certification d’aptitude, la calibration empirique des seuils d’exclusion et de compétence constitue une étape critique. Supposons qu’un examen de qualification professionnelle se compose de 80 questions à choix multiple (QCM), comportant chacune quatre alternatives de réponse (dont une seule correcte). La probabilité de succès d’un candidat répondant de façon purement stochastique est de p = 0,25.
Le comité de certification souhaite définir la règle d’admission suivante : fixer le score minimal d’admission kseuil de manière à ce qu’un candidat opérant par simple devinette n’ait qu’une probabilité résiduelle strictement inférieure à α = 0,01 (1%) d’être admis par accident statistique. Ce problème revient à isoler le quantile d’ordre 1 – α = 0,99 de la distribution nulle B(80, 0,25) :
n_qcm = 80
p_devinette = 0.25
alpha_critique = 0.01
# Quantile d'ordre 1 - alpha
seuil_admissibilite = stats.binom.ppf(1.0 - alpha_critique, n=n_qcm, p=p_devinette)
# Le score requis pour admission stricte (dépasser le seuil)
score_minimal_requis = int(seuil_admissibilite) + 1
# Calcul du taux réel d'erreur de première espèce (False Positive Rate)
taux_fausse_alarme_reel = stats.binom.sf(score_minimal_requis - 1, n=n_qcm, p=p_devinette)
print(f"Quantile PPF(0.99) : {seuil_admissibilite:.0f}")
print(f"Score minimal requis pour certification: {score_minimal_requis} / {n_qcm}")
print(f"Taux d'erreur réel sous H0 : {taux_fausse_alarme_reel:.5f}")
Grâce à ce calcul, le collège d’experts est en mesure de formaliser une règle de décision diagnostique rigoureusement étayée sur le plan mathématique, garantissant la protection du test contre les réussites fortuites.
7. Visualisation graphique avancée des distributions binomiales
7.1 Tracé de la fonction de masse de probabilité avec Matplotlib
La représentation visuelle d’une distribution discrète requiert un traitement graphique spécifique distinct de celui des distributions continues. Tracer une ligne polygonale continue entre les points de probabilité induirait une fausse perception visuelle en suggérant l’existence d’états intermédiaires non entiers (par exemple 4,5 succès). La convention académique rigoureuse impose l’utilisation de diagrammes en bâtons ou d’arbres de distribution (stem plots), où chaque masse de probabilité est érigée au-dessus de son entier discret respectif.
Pour concevoir une figure répondant aux critères de publication internationale, il convient de structurer les éléments visuels selon une typographie rigoureuse, en matérialisant visuellement la valeur de l’espérance mathématique théorique par une ligne de repère orthogonale :
import matplotlib.pyplot as plt
# Configuration des paramètres esthétiques académiques
plt.rcParams['font.sans-serif'] = 'DejaVu Sans'
plt.rcParams['axes.edgecolor'] = '#333333'
plt.rcParams['axes.linewidth'] = 0.8
n_visu = 24
p_visu = 0.35
k_valeurs = np.arange(0, n_visu + 1)
pmf_valeurs = stats.binom.pmf(k_valeurs, n_visu, p_visu)
esperance = n_visu * p_visu
fig, ax = plt.subplots(figsize=(10, 5), dpi=300)
# Tracé des tiges et des marqueurs discrets
markerline, stemlines, baseline = ax.stem(
k_valeurs, pmf_valeurs,
linefmt='steelblue',
markerfmt='o',
basefmt=" "
)
plt.setp(stemlines, linewidth=1.5)
plt.setp(markerline, markersize=5, color='darkblue')
# Ligne verticale marquant l'espérance théorique
ax.axvline(esperance, color='crimson', linestyle='--', linewidth=1.2,
label=f'Espérance théorique E[X] = {esperance:.2f}')
ax.set_title(f"Fonction de masse de probabilité binomiale B(n={n_visu}, p={p_visu})", fontsize=12, pad=12)
ax.set_xlabel("Nombre de succès observés (k)", fontsize=10)
ax.set_ylabel("Probabilité P(X = k)", fontsize=10)
ax.set_xticks(k_valeurs[::2])
ax.grid(axis='y', linestyle=':', alpha=0.6)
ax.legend(frameon=True, facecolor='white', framealpha=0.9)
plt.tight_layout()
# Affichage interactif de la figure
plt.show()

Cette représentation permet de distinguer immédiatement la zone de concentration de la masse probabiliste ainsi que le sens de l’asymétrie induite par l’éloignement du paramètre p par rapport à la valeur centrale 0,5.
7.2 Superposition des données empiriques et des courbes théoriques
L’évaluation graphique de la convergence statistique repose sur la confrontation directe d’un histogramme empirique normalisé issu d’un tirage pseudo-aléatoire NumPy avec la distribution théorique exacte calculée par SciPy. Les fonctions de haut niveau de la bibliothèque seaborn, particulièrement sns.histplot, simplifient la normalisation surfacique ou fréquentielle des observations brutes.
Pour assurer une superposition mathématiquement valide, l’histogramme des données discrètes doit être configuré avec un pas unitaire discret centré sur chaque entier (discrete=True ou en définissant explicitement les intervalles de classes [k – 0,5, k + 0,5]), évitant ainsi les artefacts de tassement ou de chevauchement :
import seaborn as sns
# Paramètres du modèle
n_exp = 30
p_exp = 0.40
taille_echantillon_visu = 100_000
# Génération empirique
donnees_simulees = rng.binomial(n=n_exp, p=p_exp, size=taille_echantillon_visu)
fig, ax = plt.subplots(figsize=(11, 5.5), dpi=300)
# Histogramme empirique normalisé en probabilité relative (stat='probability')
sns.histplot(
donnees_simulees,
stat="probability",
discrete=True,
color="#90caf9",
edgecolor="#1565c0",
alpha=0.6,
label=f"Échantillon empirique (N = {taille_echantillon_visu:,})",
ax=ax
)
# Tracé théorique exact superposé
k_spectre = np.arange(0, n_exp + 1)
pmf_theorique = stats.binom.pmf(k_spectre, n_exp, p_exp)
ax.plot(k_spectre, pmf_theorique, color="crimson", marker="D", markersize=4,
linestyle="-", linewidth=1.5, label="PMF théorique SciPy")
ax.set_title(f"Convergence d'un échantillon Monte Carlo vers la distribution B({n_exp}, {p_exp})", fontsize=12)
ax.set_xlabel("Nombre de succès (k)", fontsize=10)
ax.set_ylabel("Densité de probabilité empirique", fontsize=10)
ax.set_xlim(-0.5, n_exp + 0.5)
ax.legend(frameon=True)
ax.grid(axis='y', linestyle=':', alpha=0.5)
plt.tight_layout()
plt.show()
La superposition parfaite des barres d’échantillonnage et des marqueurs analytiques apporte une démonstration visuelle percutante du bien-fondé de l’algorithme d’échantillonnage stochastique utilisé par NumPy.
7.3 Étude comparative visuelle selon les variations paramétriques
L’exploration visuelle de l’espace des paramètres constitue une approche pédagogique et analytique fondamentale pour observer l’évolution morphologique de la fonction de masse binomiale. En concevant une grille de sous-graphiques multi-panneaux (small multiples), on met en exergue l’impact conjugué du nombre d’essais n et du paramètre de probabilité p sur l’étalement de la variance et sur le coefficient d’asymétrie :
valeurs_p = [0.15, 0.50, 0.85]
valeurs_n = [10, 30, 80]
fig, axes = plt.subplots(len(valeurs_n), len(valeurs_p), figsize=(14, 10), dpi=300, sharey='row')
for i, n_val in enumerate(valeurs_n):
for j, p_val in enumerate(valeurs_p):
ax_ij = axes[i, j]
k_axe = np.arange(0, n_val + 1)
pmf_ij = stats.binom.pmf(k_axe, n_val, p_val)
ax_ij.bar(k_axe, pmf_ij, color='#2c3e50', alpha=0.7, width=0.8)
# Annotation textuelle des moments statistiques clés
moyenne_loc = n_val * p_val
variance_loc = n_val * p_val * (1 - p_val)
ax_ij.set_title(f"n = {n_val}, p = {p_val}nE={moyenne_loc:.1f}, Var={variance_loc:.2f}", fontsize=9)
ax_ij.grid(axis='y', linestyle=':', alpha=0.4)
if i == len(valeurs_n) - 1:
ax_ij.set_xlabel("Succès (k)", fontsize=9)
if j == 0:
ax_ij.set_ylabel("P(X = k)", fontsize=9)
plt.suptitle("Évolution morphologique de la fonction de masse binomiale selon n et p", fontsize=13, y=0.99)
plt.tight_layout()
plt.show()
Cette cartographie paramétrique illustre de façon limpide comment l’augmentation conjointe de n atténue l’asymétrie initiale (visible pour p = 0,15 et p = 0,85) pour faire converger la structure globale vers une morphologie symétrique en cloche quasi-gaussienne.
8. Inférence statistique et test binomial exact en Python
8.1 Formulation formelle des hypothèses statistiques nulle et alternative
L’inférence statistique autour d’un paramètre de proportion repose canoniquement sur le test binomial exact, une méthode décisionnelle non paramétrique conçue pour s’affranchir de toute approximation asymptotique. Ce test s’avère particulièrement irremplaçable lorsque la taille de l’échantillon n est réduite, condition sous laquelle le recours aux tests basés sur le test du chi-deux ou le test z de Wald induit des biais d’inférence sévères et une inflation incontrôlée du risque d’erreur de première espèce (α).
Le cadre méthodologique débute par la spécification formelle de l’hypothèse nulle, notée H0, stipulant que la probabilité de succès sous-jacente au phénomène correspond précisément à une valeur de référence théorique :
H0 : p = p0
L’expérimentateur oppose à cette assertion une hypothèse alternative H1, dont la formulation dépend strictement des prédictions théoriques en amont de l’étude :
- Test unilatéral supérieur : H1 : p > p0 (le traitement ou l’effet accroît significativement la proportion de succès).
- Test unilatéral inférieur : H1 : p < p0 (l’effet détériore ou réduit la survenue de l’événement).
- Test bilatéral symétrique : H1 : p ≠ p0 (toute déviation, positive ou négative, est considérée scientifiquement signifiante).
Dans un contexte d’essai clinique de phase précoce visant à déterminer si une thérapie novatrice surpasse le taux d’efficacité historique d’un placebo fixé à 20% (p0 = 0,20), l’adoption d’un cadre unilatéral supérieur s’impose d’emblée.
8.2 Exécution numérique avec scipy.stats.binomtest
L’écosystème SciPy a profondément modernisé ses routines de test d’hypothèse. L’ancienne fonction scipy.stats.binom_test a été officiellement dépréciée au profit de la classe d’inférence structurée scipy.stats.binomtest. Cette nouvelle API ne renvoie plus un simple flottant représentant la p-valeur, mais un objet de résultat dédié (BinomialTestResult) encapsulant la statistique de test, la p-valeur exacte et les méthodes de dérivation d’intervalles de confiance associés :
from scipy.stats import binomtest
# Protocole expérimental : cohorte de 35 patients, 13 rémissions observées
essais_cliniques_n = 35
remissions_observees_k = 13
taux_placebo_p0 = 0.20
# Exécution du test binomial exact unilatéral supérieur (H1 : p > 0.20)
resultat_test = binomtest(
k=remissions_observees_k,
n=essais_cliniques_n,
p=taux_placebo_p0,
alternative='greater'
)
print(f"Statistique k observée : {resultat_test.k}")
print(f"Nombre total d'essais n: {resultat_test.n}")
print(f"Valeur p (p-value) : {resultat_test.pvalue:.6f}")
print(f"Rejet de H0 au seuil alpha=0.05 : {resultat_test.pvalue < 0.05}")
Pour un test bilatéral (alternative='two-sided'), la définition computationnelle de la p-valeur requiert une précision rigoureuse : il s’agit de la somme des probabilités de l’ensemble des issues entières i dont la probabilité élémentaire sous H0 est inférieure ou égale à celle de l’événement observé :
p-value = ∑{i : P(X = i) ≤ P(X = k)} P(X = i)
Cette approche, dite de méthode des ordonnées faibles, est la plus conservatrice et la plus reconnue au sein de la littérature statistique internationale.
8.3 Intervalles de confiance de Clopper-Pearson pour la proportion
Dans la restitution de résultats d’inférence, la seule présentation d’une p-valeur est jugée insuffisante au regard des exigences de la reproductibilité scientifique ; elle doit impérativement être adjointe à un intervalle de confiance délimitant l’amplitude de l’effet. L’intervalle de confiance standard de Wald, enseigné traditionnellement dans les cours d’introduction selon l’équation :
p̂ ± z1 – α/2 √((p̂(1 – p̂)) / n)
présente des défaillances systématiques majeures lorsque n est petit ou lorsque p s’approche des frontières 0 ou 1, conduisant à des couvertures réelles très inférieures au niveau nominal 1 – α, voire à des bornes absurdes situées en dehors du domaine [0, 1].
Pour remédier à cette tare, l’intervalle de Clopper-Pearson fournit un intervalle exact non asymptotique dérivé directement de la distribution binomiale via la loi Bêta. Cet intervalle garantit formellement que la probabilité de couverture réelle est toujours supérieure ou égale au niveau de confiance nominal 1 – α. L’objet BinomialTestResult permet d’extraire directement cet intervalle via sa méthode proportion_ci() :
# Extraction de l'intervalle de confiance exact de Clopper-Pearson à 95%
intervalle_cp = resultat_test.proportion_ci(confidence_level=0.95, method='exact')
print(f"Proportion observée (p chapeau) : {resultat_test.k / resultat_test.n:.4f}")
print(f"Intervalle de Clopper-Pearson 95%: [{intervalle_cp.low:.4f}, {intervalle_cp.high:.4f}]")
# Comparaison avec les intervalles asymptotiques alternatifs (Wilson, Agresti-Coull)
intervalle_wilson = resultat_test.proportion_ci(confidence_level=0.95, method='wilson')
print(f"Intervalle de score de Wilson 95% : [{intervalle_wilson.low:.4f}, {intervalle_wilson.high:.4f}]")
Le recours à la méthode method='exact' (Clopper-Pearson) constitue la norme méthodologique d’excellence pour l’ensemble des études comportementales, psychologiques et biomédicales publiées dans des revues à comité de lecture.
9. Approximations asymptotiques : loi normale et loi de Poisson
9.1 Théorème de De Moivre-Laplace et approximation gaussienne
Le théorème de De Moivre-Laplace, cas particulier précurseur du théorème central limite formalisé dès le XVIIIe siècle, démontre qu’à mesure que le nombre d’essais n croît vers l’infini, la distribution discrète d’une variable aléatoire binomiale X ~ B(n, p) converge en loi vers une distribution continue normale (gaussienne) :
X →d N(μ, σ2), avec μ = np et σ2 = np(1 – p)
Historiquement indispensable pour contourner l’impossibilité de calculer des factoriels titanesques à la main, cette approximation conserve aujourd’hui un intérêt conceptuel majeur dans la théorie asymptotique et l’estimation analytique rapide. Pour que l’erreur d’approximation soit tolérable, les critères de validité traditionnels exigent simultanément :
np ≥ 5 et n(1 – p) ≥ 5 (ou de manière plus prudente np ≥ 10 et n(1 – p) ≥ 10)
Nous pouvons concevoir un script Python comparant la fonction de masse exacte et la densité de probabilité normale correspondante à travers scipy.stats.norm, tout en quantifiant la divergence numérique :
n_asympt = 100
p_asympt = 0.35
# Paramètres de la loi normale limite
mu_normale = n_asympt * p_asympt
sigma_normale = np.sqrt(n_asympt * p_asympt * (1 - p_asympt))
k_vals = np.arange(0, n_asympt + 1)
pmf_exacte = stats.binom.pmf(k_vals, n_asympt, p_asympt)
pdf_approx = stats.norm.pdf(k_vals, loc=mu_normale, scale=sigma_normale)
# Calcul de l'erreur absolue maximale (norme L-infinie)
erreur_maximale = np.max(np.abs(pmf_exacte - pdf_approx))
print(f"Erreur absolue maximale de l'approximation normale : {erreur_maximale:.6f}")
9.2 Technique et impact de la correction de continuité
Le passage d’une distribution discrète (définie sur les entiers ℤ) à une distribution continue (définie sur ℝ) soulève un paradoxe géométrique élémentaire : sous une loi normale continue, la probabilité d’un point isolé est formellement nulle P(Y = k) = 0. Pour approximer adéquatement la masse ponctuelle d’un entier k ou une somme cumulée, il est indispensable de procéder à un réajustement géométrique connu sous le nom de correction de continuité (dite de Yates).
Ce procédé consiste à étendre la valeur entière k sur son intervalle de continuité réel unitaire [k – 0,5, k + 0,5]. Dès lors, l’approximation de la masse ponctuelle devient :
P(X = k) ≈ P(k – 0,5 ≤ Y ≤ k + 0,5) = Φ((k + 0,5 – μ) / σ) – Φ((k – 0,5 – μ) / σ)
De même, pour une probabilité cumulée unilatérale :
P(X ≤ k) ≈ P(Y ≤ k + 0,5) = Φ((k + 0,5 – μ) / σ)
k_cible = 42
# 1. Calcul exact binomial
proba_vraie = stats.binom.cdf(k_cible, n_asympt, p_asympt)
# 2. Approximation normale brute (sans correction de continuité)
approx_brute = stats.norm.cdf(k_cible, loc=mu_normale, scale=sigma_normale)
# 3. Approximation normale avec correction de continuité (+ 0.5)
approx_corrigee = stats.norm.cdf(k_cible + 0.5, loc=mu_normale, scale=sigma_normale)
print(f"Probabilité réelle binomiale P(X <= {k_cible}) : {proba_vraie:.8f}")
print(f"Approx. normale sans correction : {approx_brute:.8f} (Erreur : {abs(proba_vraie - approx_brute):.2e})")
print(f"Approx. normale avec correction (+0.5) : {approx_corrigee:.8f} (Erreur : {abs(proba_vraie - approx_corrigee):.2e})")
L’introduction de la correction de continuité réduit l’erreur d’approximation d’un ordre de grandeur substantiel, confirmant son rôle régulateur indispensable lors de l’emploi des méthodes décisionnelles asymptotiques.
9.3 Convergence vers la loi de Poisson pour les événements rares
Lorsque le nombre d’épreuves n tend vers l’infini tandis que la probabilité p converge vers zéro de telle sorte que le produit λ = np demeure une constante finie strictement positive, la loi binomiale converge non pas vers une loi normale, mais vers une loi de Poisson de paramètre λ (loi des événements rares) :
limn → ∞, p → 0 &Binomial(n, k); pk(1 – p)n – k = (e-λ λk) / k!
Cette convergence est particulièrement opérante en neurosciences comportementales et en génétique, où l’on observe la fréquence d’apparition de mutations ponctuelles ou le déclenchement de potentiels d’action miniatures sur des échelles de temps infinitésimales. Nous pouvons mesurer la divergence informationnelle entre la loi binomiale et son approximation de Poisson au moyen de la divergence de Kullback-Leibler (KL) :
from scipy.special import rel_entr
n_poisson = 1000
p_poisson = 0.004
lambda_param = n_poisson * p_poisson # lambda = 4.0
k_support = np.arange(0, 25)
p_binom = stats.binom.pmf(k_support, n_poisson, p_poisson)
p_pois = stats.poisson.pmf(k_support, mu=lambda_param)
# Calcul de la divergence de Kullback-Leibler D_KL(Binomiale || Poisson)
# rel_entr calcule p * log(p / q) élément par élément
kl_divergence = np.sum(rel_entr(p_binom, p_pois))
print(f"Paramètre lambda : {lambda_param}")
print(f"Divergence d'information de Kullback-Leibler : {kl_divergence:.8e} nats")
Une divergence de Kullback-Leibler de l’ordre de 10-6 atteste d’une identité distributionnelle quasi-parfaite, autorisant l’usage substitutif de la distribution de Poisson dans les systèmes à flux d’événements continus.
10. Inférence bayésienne et modèle conjugué Bêta-Binomial
10.1 Principes de l’actualisation bayésienne pour un processus binomial
Contrairement au paradigme fréquentiste qui considère le paramètre p comme une valeur scalaire fixe mais inconnue, le paradigme bayésien appréhende p comme une variable aléatoire continue sur laquelle pèse une incertitude épistémique, représentée par une distribution de probabilité. L’actualisation bayésienne consiste à réviser une distribution a priori P(p) à la lumière des données empiriques observées D = (k, n) via le théorème de Bayes :
P(p | k, n) = (P(k | n, p) × P(p)) / P(k | n)
où P(k | n, p) correspond à la fonction de vraisemblance binomiale. L’un des piliers de l’analyse stochastique bayésienne est la propriété de conjugaison : lorsque la distribution a priori appartient à la même famille fonctionnelle que la distribution a posteriori, le problème admet une solution analytique exacte sans nécessiter de méthodes d’échantillonnage MCMC (Markov Chain Monte Carlo).
Pour la vraisemblance binomiale, la famille conjuguée est la distribution Bêta, définie par les hyperparamètres α > 0 et β > 0. Si le prior est spécifié comme p ~ Beta(α, β), la distribution conjointe s’énonce :
P(p | k, n) ∝ [pk(1 – p)n – k] × [pα – 1(1 – p)β – 1] = p(α + k) – 1(1 – p)(β + n – k) – 1
Par identification immédiate, la distribution a posteriori est formellement une loi Bêta actualisée :
p | D ~ Beta(αpost, βpost) = Beta(α + k, β + n – k)
Cette élégance calculatoire permet de réaliser des actualisations continues en temps réel : les hyperparamètres α et β jouent le rôle de « pseudo-comptages » préalables de succès et d’échecs.
10.2 Implémentation sous Python avec scipy.stats.beta
Le module scipy.stats.beta offre l’ensemble de l’outillage mathématique pour formaliser cette mise à jour analytique. Considérons le cas où nous démarrons avec un a priori non-informatif de Bayes-Laplace (prior uniforme Beta(1, 1)). Nous soumettons ensuite cet a priori à l’observation séquentielle d’un protocole expérimental cumulant k = 18 succès sur n = 25 essais :
# Définition des hyperparamètres a priori (Uniforme / Non-informatif)
alpha_prior = 1.0
beta_prior = 1.0
# Données collectées
n_obs = 25
k_obs = 18
# Actualisation analytique bayésienne
alpha_post = alpha_prior + k_obs
beta_post = beta_prior + (n_obs - k_obs)
# Moments a posteriori
moyenne_post = stats.beta.mean(alpha_post, beta_post)
variance_post = stats.beta.var(alpha_post, beta_post)
# Calcul d'un intervalle de crédibilité bayésien à 95% (Equal-tailed credible interval)
ic_bayesian = stats.beta.ppf([0.025, 0.975], alpha_post, beta_post)
print(f"Distribution a posteriori : Beta(alpha={alpha_post}, beta={beta_post})")
print(f"Moyenne a posteriori (E[p|D]) : {moyenne_post:.4f}")
print(f"Intervalle de crédibilité à 95% : [{ic_bayesian[0]:.4f}, {ic_bayesian[1]:.4f}]")
L’intervalle de crédibilité ainsi dérivé possède une interprétation épistémique directe, contrairement à l’intervalle de confiance fréquentiste : l’expérimentateur peut légitimement affirmer qu’il existe 95% de probabilité subjective que le paramètre latent p appartienne effectivement à l’intervalle [0,5401 ; 0,8542].
10.3 Application à l’apprentissage et à l’adaptation cognitive
L’inférence bayésienne fournit un cadre d’une fécondité exceptionnelle pour modéliser la dynamique computationnelle de l’apprentissage chez l’humain ou l’animal. Selon la théorie du cerveau bayésien (Bayesian Brain Hypothesis), les structures corticales maintiennent des représentations probabilistes du monde extérieur et révisent séquentiellement leurs croyances à mesure que les retours environnementaux (récompenses ou punitions) surviennent.
Le script suivant illustre l’ajustement dynamique des croyances d’un sujet au fil d’une tâche d’apprentissage probabiliste comportant 15 essais consécutifs :
# Séquence temporelle de réponses (1 = Succès / Récompense, 0 = Échec)
flux_essais = np.array([1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1])
alpha_courant = 2.0 # A priori modérément sceptique
beta_courant = 2.0
historique_croyances = []
for t, essai in enumerate(flux_essais, start=1):
# Mise à jour séquentielle réponse par réponse
alpha_courant += essai
beta_courant += (1 - essai)
mode_a_posteriori = (alpha_courant - 1) / (alpha_courant + beta_courant - 2)
ecart_type_post = np.sqrt(stats.beta.var(alpha_courant, beta_courant))
historique_croyances.append({
'essai': t,
'reponse': essai,
'mode_p': mode_a_posteriori,
'incertitude_sigma': ecart_type_post
})
df_apprentissage = pd.DataFrame(historique_croyances)
print(df_apprentissage[['essai', 'reponse', 'mode_p', 'incertitude_sigma']].to_string(index=False))
On constate que l’incertitude épistémique (matérialisée par l’écart-type a posteriori) décroît de manière continue, démontrant comment l’intégration séquentielle de flux de données binomiales affine la précision représentationnelle d’un agent cognitif.
11. Modélisation par régression logistique et processus binomiaux
11.1 Extension au modèle linéaire généralisé (GLM)
Jusqu’à présent, nous avons traité le paramètre de succès p comme une constante invariante au sein d’une condition donnée. Néanmoins, dans les systèmes naturels complexes, la probabilité d’un succès dépend fréquemment d’un faisceau de covariables continues et catégorielles (âge, dose pharmacologique, temps de réaction, score d’attention). Le cadre théorique unifié permettant d’exprimer le succès binomial en fonction de prédicteurs multivariés est le Modèle Linéaire Généralisé (GLM), formalisé par John Nelder et Robert Wedderburn (1972).
Puisque le paramètre de probabilité p est strictement borné dans l’intervalle [0, 1], une combinaison linéaire classique des prédicteurs η = β0 + ∑ βjXj ne peut pas être ajustée directement, sous peine de prédire des probabilités aberrantes inférieures à 0 ou supérieures à 1. Le modèle introduit donc une fonction de lien monotone et différentiable g(p) faisant correspondre [0, 1] à l’espace des réels (-∞, +∞). Pour la distribution binomiale, le lien canonique par excellence est la fonction logit (log-odds ou logarithme du ratio de cotes) :
g(p) = ln(p / (1 – p)) = η = Xβ
L’inversion de cette équation établit la fonction de réponse logistique liant directement la probabilité conditionnelle au prédicteur linéaire :
p(X) = 1 / (1 + e–Xβ)
Il est fondamental de distinguer deux formats de données acceptés par les GLM binomiaux : les données unitaires non groupées (régression logistique binaire standard de type Bernoulli, où chaque ligne représente un essai unique codé 0 ou 1) et les données groupées agrégées, où chaque ligne de la matrice modélise une cohorte caractérisée par un couple (ksucces, nessais).
11.2 Ajustement d’un modèle binomial avec statsmodels
La bibliothèque statsmodels constitue l’environnement de référence pour l’estimation rigoureuse des modèles linéaires généralisés sous Python. Contrairement à scikit-learn, qui est principalement orienté vers la performance prédictive et la régularisation machine learning, statsmodels fournit des tables de dérivation complètes des statistiques d’inférence (erreurs standards asymptotiques, statistiques de Wald, valeurs z, intervalles de confiance des coefficients et métriques de déviance).
Considérons l’ajustement d’un modèle binomial groupé évaluant le taux de rétention de participants à un protocole clinique en fonction de la dose médicamenteuse administrée :
import statsmodels.api as sm
# Données synthétiques groupées : doses, essais par condition, succès observés
doses = np.array([5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0])
nb_sujets_par_dose = np.array([40, 40, 40, 40, 40, 40, 40, 40])
nb_succes = np.array([6, 11, 16, 21, 27, 31, 35, 38])
# Calcul du vecteur des échecs (requis pour l'estimation binomiale groupée)
nb_echecs = nb_sujets_par_dose - nb_succes
# Matrice des réponses bivariées : [succès, échecs]
reponse_binomiale = np.column_stack((nb_succes, nb_echecs))
# Ajout d'une constante pour l'intercept
X_matrice = sm.add_constant(doses)
# Instanciation et ajustement du modèle GLM avec la famille Binomiale
modele_glm = sm.GLM(
reponse_binomiale,
X_matrice,
family=sm.families.Binomial(link=sm.families.links.Logit())
)
resultats_glm = modele_glm.fit()
# Affichage des métriques académiques
print(resultats_glm.summary())
L’exponentiation des coefficients estimés (eβ1) permet d’obtenir directement les Odds Ratios (ratios de cotes), indiquant la multiplication relative de la cote de succès induite par l’augmentation d’une unité de la variable explicative.
11.3 Diagnostic de surdispersion et extensions quasi-binomiales
L’une des hypothèses les plus restrictives du modèle linéaire généralisé binomial réside dans la rigidité de sa structure de variance : pour une probabilité moyenne p̂, la variance théorique imposée est strictement σ2 = np̂(1 – p̂). Or, dans la pratique de la recherche écologique, comportementale ou médicale, les données empiriques présentent fréquemment une dispersion excédant cette prédiction théorique, une pathologie statistique désignée sous le nom de surdispersion (overdispersion).
Cette surdispersion découle généralement de l’hétérogénéité non observée au sein des sujets, de corrélations intraclasses (sujets nichés au sein d’une même cohorte) ou de contaminations stochastiques. Le diagnostic de surdispersion s’évalue en divisant la statistique du chi-deux de Pearson (ΧP2) par le nombre de degrés de liberté résiduels (ddl) du modèle :
φ = ΧP2 / ddlresiduels
Un ratio φ significativement supérieur à 1,0 (typiquement > 1,25) atteste formellement de la présence d’une surdispersion. Si l’expérimentateur ignore cette anomalie, le modèle sous-estimera l’ampleur des erreurs standards des coefficients, augmentant dramatiquement le risque de déclarer à tort un effet statistiquement significatif (faux positifs). La correction computationnelle requiert l’estimation d’un modèle quasi-binomial, qui incorpore un facteur d’échelle empirique φ dans la matrice de covariance des paramètres, ou l’adoption d’un modèle de mélange comme la distribution bêta-binomiale.
# Diagnostic du paramètre d'échelle (dispersion)
chi2_pearson = resultats_glm.pearson_chi2
ddl_residuels = resultats_glm.df_resid
dispersion_estimee = chi2_pearson / ddl_residuels
print(f"Statistique Chi2 de Pearson : {chi2_pearson:.3f}")
print(f"Degrés de liberté résiduels : {ddl_residuels}")
print(f"Paramètre de dispersion phi : {dispersion_estimee:.3f}")
if dispersion_estimee > 1.25:
print("Alerte : Surdispersion détectée. Recours aux erreurs types robustes recommandé.")
else:
print("Homogénéité de la variance validée : absence de surdispersion critique.")
12. Études de cas appliquées aux sciences du comportement et neurosciences cognitives
12.1 Modélisation en théorie de la détection du signal (TDS)
La Théorie de la Détection du Signal (TDS), introduite par David Green et John Swets (1966), est le cadre computationnel de référence pour modéliser la prise de décision perceptive en situation d’incertitude. Face à une séquence d’essais où un stimulus cible peut être présent ou absent, le comportement d’un observateur se décompose en quatre catégories disjointes : les détections correctes (Hits), les fausses alarmes (False Alarms), les omissions (Misses) et les rejets corrects (Correct Rejections).
Puisque les détections correctes et les fausses alarmes procèdent de tirages indépendants régis par la loi binomiale au sein de leurs blocs respectifs (nstimulus et nbruit), nous pouvons modéliser la variabilité stochastique des indices de sensibilité discriminative d’ (d-prime) et du critère décisionnel c au moyen de simulations Monte Carlo :
d’ = Φ-1(Taux de Hits) – Φ-1(Taux de Fausses Alarmes)
c = -0,5 × [Φ-1(Taux de Hits) + Φ-1(Taux de Fausses Alarmes)]
def simuler_tds_monte_carlo(n_essais_signal: int, n_essais_bruit: int,
p_hit_latente: float, p_fa_latente: float,
n_iterations: int = 10_000) -> pd.DataFrame:
"""
Simule la variabilité d'échantillonnage des estimateurs TDS sous loi binomiale.
"""
# Tirages stochastiques des réalisations empiriques
succes_hits = rng.binomial(n=n_essais_signal, p=p_hit_latente, size=n_iterations)
succes_fa = rng.binomial(n=n_essais_bruit, p=p_fa_latente, size=n_iterations)
# Correction de Hautus (1995) pour prévenir les probabilités extrêmes de 0 ou 1
taux_hit = (succes_hits + 0.5) / (n_essais_signal + 1.0)
taux_fa = (succes_fa + 0.5) / (n_essais_bruit + 1.0)
# Inversion par la fonction quantile normale inverse
z_hit = stats.norm.ppf(taux_hit)
z_fa = stats.norm.ppf(taux_fa)
d_prime = z_hit - z_fa
critere_c = -0.5 * (z_hit + z_fa)
return pd.DataFrame({'d_prime': d_prime, 'critere_c': critere_c})
# Paramétrage pour un protocole psychophysique visuel
df_tds = simuler_tds_monte_carlo(n_essais_signal=80, n_essais_bruit=80,
p_hit_latente=0.78, p_fa_latente=0.18)
print("Distribution empirique des estimateurs TDS après 10 000 simulations :")
print(df_tds.describe().loc[['mean', 'std', '25%', '50%', '75%']])
Cette approche permet aux psychophysiciens d’estimer avec précision l’erreur standard asymptotique des paramètres de détection perceptive sans nécessiter d’approximations théoriques complexes.
12.2 Analyse des temps de réaction et taux d’erreurs (Tâche de Stroop / Go-NoGo)
Les paradigmes d’inhibition comportementale, à l’instar de la tâche Go/No-Go ou de l’effet d’interférence de Stroop, reposent sur l’analyse de compromis vitesse-précision (speed-accuracy trade-off). Dans une épreuve Go/No-Go, l’expérimentateur enregistre la fréquence à laquelle un participant échoue à retenir son action motrice lors de l’apparition d’un stimulus d’inhibition (erreur de commission). Cet événement est un processus purement binomial.
Pour mesurer formellement l’effet d’une manipulation expérimentale (par exemple la privation de sommeil sur l’inhibition motrice), nous pouvons mettre en œuvre un test de comparaison de deux proportions binomiales appariées ou indépendantes au sein de cohortes d’essais :
from statsmodels.stats.proportion import proportions_ztest
# Cohorte A : Sujets reposés (120 essais No-Go, 14 erreurs de commission)
essais_no_go_repos = 120
erreurs_repos = 14
# Cohorte B : Sujets en privation de sommeil (120 essais No-Go, 33 erreurs de commission)
essais_no_go_privation = 120
erreurs_privation = 33
comptages = np.array([erreurs_privation, erreurs_repos])
observations = np.array([essais_no_go_privation, essais_no_go_repos])
# Test z de comparaison de deux proportions indépendantes
stat_z, p_valeur_inhibition = proportions_ztest(count=comptages, nobs=observations, alternative='greater')
taux_erreur_repos = erreurs_repos / essais_no_go_repos
taux_erreur_privation = erreurs_privation / essais_no_go_privation
print(f"Taux d'erreur Repos : {taux_erreur_repos:.3f}")
print(f"Taux d'erreur Privation : {taux_erreur_privation:.3f}")
print(f"Statistique z de Wald : {stat_z:.4f}")
print(f"Significativité p-value : {p_valeur_inhibition:.6e}")
L’écart hautement significatif (p < 0,001) valide statistiquement la dégradation sélective de l’inhibition préfrontale consécutive à la privation de sommeil.
12.3 Détection automatisée des biais de réponse et simulation de cohortes
L’évaluation rigoureuse de protocoles expérimentaux requiert l’implémentation de filtres algorithmiques de contrôle qualité automatisés. Dans les études comportementales en ligne à grande échelle (menées par exemple via Prolific ou Mechanical Turk), certains participants synthétiques ou inattentifs répondent de manière totalement stéréotypée (par exemple en sélectionnant systématiquement la touche « Gauche » dans 98% des essais d’un protocole binaire).
Il est aisé de concevoir un pipeline de détection fondé sur une batterie de tests binomiaux séquentiels pour auditer l’intégrité stochastique des réponses :
def detecter_participants_aberrants(matrice_reponses: np.ndarray, seuil_alpha: float = 0.001) -> np.ndarray:
"""
Identifie les participants présentant des biais directionnels non aléatoires
sur une matrice de choix binaires (0 ou 1) de forme (n_sujets, n_essais).
"""
n_sujets, n_essais = matrice_reponses.shape
succes_par_sujet = np.sum(matrice_reponses, axis=1)
indices_aberrants = []
for i in range(n_sujets):
# Test binomial bilatéral sous l'hypothèse d'équiprobabilité spatiale (p = 0.5)
k = succes_par_sujet[i]
resultat = stats.binomtest(k=k, n=n_essais, p=0.5, alternative='two-sided')
if resultat.pvalue Succès : {k_score}/100, p-valeur = {p_val:.3e}")
Cette architecture computationnelle assure une purification automatisée des données avant tout traitement statistique lourd, incarnant la convergence de la rigueur mathématique et de l’ingénierie logicielle permise par l’écosystème Python contemporain.
Références
- Bernoulli, J. (1713). Ars Conjectandi, Opus Posthumum. Basileae: Impensis Thurnisiorum, Fratrum.
- Borel, É. (1909). Les probabilités dénombrables et leurs applications arithmétiques. Rendiconti del Circolo Matematico di Palermo, 27(1), 247–271. https://doi.org/10.1007/BF03019651
- Clopper, C. J., & Pearson, E. S. (1934). The use of confidence or fiducial limits illustrated in the case of the binomial. Biometrika, 26(4), 404–413. https://doi.org/10.1093/biomet/26.4.404
- Green, D. M., & Swets, J. A. (1966). Signal Detection Theory and Psychophysics. John Wiley & Sons.
- 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
- Hautus, M. J. (1995). Corrections for extreme proportions and their biasing effects on estimated values of d’. Behavior Research Methods, Instruments, & Computers, 27(1), 46–51. https://doi.org/10.3758/BF03203619
- Nelder, J. A., & Wedderburn, R. W. (1972). Generalized linear models. Journal of the Royal Statistical Society: Series A (General), 135(3), 370–384. https://doi.org/10.2307/2344614
- O’Neill, M. E. (2014). PCG: A family of simple fast space-efficient statistically good algorithms for random number generation (HMC-CS-2014-0905). Harvey Mudd College.
- Virtanen, P., Gommers, R., Oliphant, T. E., Haberland, M., Reddy, T., Cournapeau, D., … & SciPy 1.0 Contributors. (2020). SciPy 1.0: Fundamental algorithms for scientific computing in Python. Nature Methods, 17(3), 261–272. https://doi.org/10.1038/s41592-019-0686-2