"statistics" — Fonctions mathématiques pour les statistiques
************************************************************

Nouveau dans la version 3.4.

**Code source :** Lib/statistics.py

======================================================================

Ce module fournit des fonctions pour le calcul de valeurs statistiques
sur des données numériques (valeurs réelles de la classe "Real").

Ce module n'est pas pensé comme substitut à des bibliothèques tierces
telles que NumPy, SciPy ou des suites logicielles propriétaires
complètes à destination des statisticiens professionnels comme
Minitab, SAS ou Matlab. Ce module se situe au niveau des calculatrices
scientifiques graphiques.

À moins que cela ne soit précisé différemment, ces fonctions gèrent
les objets "int", "float", "Decimal" et "Fraction". Leur bon
comportement avec d'autres types (numériques ou non) n'est pas
garanti. Le comportement de ces fonctions sur des collections mixtes
de différents types est indéfini et dépend de l'implémentation. Si vos
données comportement un mélange de plusieurs types, vous pouvez
utiliser "map()" pour vous assurer que le résultat est cohérent, par
exemple : "map(float, input_data)".


Moyennes et mesures de la tendance centrale
===========================================

Ces fonctions calculent une moyenne ou une valeur typique à partir
d'une population ou d'un échantillon.

+-------------------------+-----------------------------------------------------------------+
| "mean()"                | Moyenne arithmétique des données.                               |
+-------------------------+-----------------------------------------------------------------+
| "fmean()"               | Moyenne arithmétique rapide en calcul à virgule flottante.      |
+-------------------------+-----------------------------------------------------------------+
| "geometric_mean()"      | Moyenne géométrique des données.                                |
+-------------------------+-----------------------------------------------------------------+
| "harmonic_mean()"       | Moyenne harmonique des données.                                 |
+-------------------------+-----------------------------------------------------------------+
| "median()"              | Médiane (valeur centrale) des données.                          |
+-------------------------+-----------------------------------------------------------------+
| "median_low()"          | Médiane basse des données.                                      |
+-------------------------+-----------------------------------------------------------------+
| "median_high()"         | Médiane haute des données.                                      |
+-------------------------+-----------------------------------------------------------------+
| "median_grouped()"      | Médiane de données groupées, calculée comme le 50^e percentile. |
+-------------------------+-----------------------------------------------------------------+
| "mode()"                | Mode principal (la valeur la plus représentée) de données       |
|                         | discrètes ou nominales.                                         |
+-------------------------+-----------------------------------------------------------------+
| "multimode()"           | Liste des modes (les valeurs les plus représentées) de données  |
|                         | discrètes ou nominales.                                         |
+-------------------------+-----------------------------------------------------------------+
| "quantiles()"           | Divise les données en intervalles de même probabilité.          |
+-------------------------+-----------------------------------------------------------------+


Mesures de la dispersion
========================

Ces fonctions mesurent la tendance de la population ou d'un
échantillon à dévier des valeurs typiques ou des valeurs moyennes.

+-------------------------+-----------------------------------------------+
| "pstdev()"              | Écart-type de la population.                  |
+-------------------------+-----------------------------------------------+
| "pvariance()"           | Variance de la population.                    |
+-------------------------+-----------------------------------------------+
| "stdev()"               | Écart-type d'un échantillon.                  |
+-------------------------+-----------------------------------------------+
| "variance()"            | Variance d'un échantillon.                    |
+-------------------------+-----------------------------------------------+


Détails des fonctions
=====================

Note : les fonctions ne requièrent pas que les données soient
ordonnées. Toutefois, pour en faciliter la lecture, les exemples
utiliseront des séquences croissantes.

statistics.mean(data)

   Renvoie la moyenne arithmétique de l'échantillon *data* qui peut
   être une séquence ou un itérable.

   La moyenne arithmétique est la somme des valeurs divisée par le
   nombre d'observations. Il s'agit de la valeur couramment désignée
   comme la « moyenne » bien qu'il existe de multiples façons de
   définir mathématiquement la moyenne. C'est une mesure de la
   tendance centrale des données.

   Une erreur "StatisticsError" est levée si *data* est vide.

   Exemples d'utilisation :

      >>> mean([1, 2, 3, 4, 4])
      2.8
      >>> mean([-1.0, 2.5, 3.25, 5.75])
      2.625

      >>> from fractions import Fraction as F
      >>> mean([F(3, 7), F(1, 21), F(5, 3), F(1, 3)])
      Fraction(13, 21)

      >>> from decimal import Decimal as D
      >>> mean([D("0.5"), D("0.75"), D("0.625"), D("0.375")])
      Decimal('0.5625')

   Note:

     La moyenne arithmétique est fortement impactée par la présence de
     valeurs aberrantes et n'est pas un estimateur robuste de la
     tendance centrale : la moyenne n'est pas nécessairement un
     exemple représentatif de l'échantillon. Voir "median()" et
     "mode()" pour des mesures plus robustes de la tendance
     centrale.La moyenne de l'échantillon est une estimation non
     biaisée de la moyenne de la véritable population. Ainsi, en
     calculant la moyenne sur tous les échantillons possibles,
     "mean(sample)" converge vers la moyenne réelle de la population
     entière. Si *data* est une population entière plutôt qu'un
     échantillon, alors "mean(data)" équivaut à calculer la véritable
     moyenne μ.

statistics.fmean(data)

   Convertit *data* en nombres à virgule flottante et calcule la
   moyenne arithmétique.

   Cette fonction est plus rapide que "mean()" et renvoie toujours un
   "float". *data* peut être une séquence ou un itérable. Si les
   données d'entrée sont vides, la fonction lève une erreur
   "StatisticsError".

      >>> fmean([3.5, 4.0, 5.25])
      4.25

   Nouveau dans la version 3.8.

statistics.geometric_mean(data)

   Convertit *data* en nombres à virgule flottante et calcule la
   moyenne géométrique.

   La moyenne géométrique mesure la tendance centrale ou la valeur
   typique de *data* en utilisant le produit des valeurs (par
   opposition à la moyenne arithmétique qui utilise la somme).

   Lève une erreur "StatisticsError" si les données sont vides, si
   elles contiennent un zéro ou une valeur négative. *data* peut être
   une séquence ou un itérable.

   Aucune mesure particulière n'est prise pour garantir que le
   résultat est parfaitement exact (cela peut toutefois changer dans
   une version future).

      >>> round(geometric_mean([54, 24, 36]), 1)
      36.0

   Nouveau dans la version 3.8.

statistics.harmonic_mean(data)

   Renvoie la moyenne harmonique de *data*, une séquence ou un
   itérable de nombres réels.

   La moyenne harmonique est l'inverse de la moyenne arithmétique
   "mean()" des inverses. Par exemple, la moyenne harmonique de trois
   valeurs *a*, *b* et *c* vaut "3/(1/a + 1/b + 1/c)". Si une des
   valeurs est nulle, alors le résultat est zéro.

   La moyenne harmonique est un type de moyenne, une mesure de la
   tendance centrale des données. Elle est généralement appropriée
   pour calculer des moyennes de taux ou de proportions, par exemple
   des vitesses.

   Supposons qu'une voiture parcoure 10 km à 40 km/h puis 10 km à 60
   km/h. Quelle a été sa vitesse moyenne ?

      >>> harmonic_mean([40, 60])
      48.0

   Supposons qu'un investisseur achète autant de parts dans trois
   compagnies chacune de ratio cours sur bénéfices (*P/E*) 2,5, 3 et
   10. Quel est le ratio cours sur bénéfices moyen du portefeuille de
   l'investisseur ?

      >>> harmonic_mean([2.5, 3, 10])  # For an equal investment portfolio.
      3.6

   Une erreur "StatisticsError" est levée si *data* est vide ou si
   l'un de ses éléments est inférieur à zéro.

   L'algorithme actuellement implémenté s'arrête prématurément lors de
   la rencontre d'un zéro dans le parcours de l'entrée. Cela signifie
   que la validité des valeurs suivantes n'est pas testée (ce
   comportement est susceptible de changer dans une version future).

   Nouveau dans la version 3.6.

statistics.median(data)

   Renvoie la médiane (la valeur centrale) de données numériques en
   utilisant la méthode classique « moyenne des deux du milieu ». Lève
   une erreur "StatisticsError" si *data* est vide. *data* peut être
   une séquence ou un itérable.

   La médiane est une mesure robuste de la tendance centrale et est
   moins sensible à la présence de valeurs aberrantes que la moyenne.
   Lorsque le nombre d'observations est impair, la valeur du milieu
   est renvoyée :

      >>> median([1, 3, 5])
      3

   Lorsque le nombre d'observations est pair, la médiane est
   interpolée en calculant la moyenne des deux valeurs du milieu :

      >>> median([1, 3, 5, 7])
      4.0

   Cette approche est adaptée à des données discrètes à condition que
   vous acceptiez que la médiane ne fasse pas nécessairement partie
   des observations.

   Si les données sont ordinales (elles peuvent être ordonnées) mais
   pas numériques (elles ne peuvent être additionnées), utilisez
   "median_low()" ou "median_high()" à la place.

statistics.median_low(data)

   Renvoie la médiane basse de données numériques. Lève une erreur
   "StatisticsError" si *data* est vide. *data* peut être une séquence
   ou un itérable.

   La médiane basse est toujours une valeur représentée dans les
   données. Lorsque le nombre d'observations est impair, la valeur du
   milieu est renvoyée. Sinon, la plus petite des deux valeurs du
   milieu est renvoyée.

      >>> median_low([1, 3, 5])
      3
      >>> median_low([1, 3, 5, 7])
      3

   Utilisez la médiane basse lorsque vos données sont discrètes et que
   vous préférez que la médiane soit une valeur représentée dans vos
   observations plutôt que le résultat d'une interpolation.

statistics.median_high(data)

   Renvoie la médiane haute des données. Lève une erreur
   "StatisticsError" si *data* est vide. *data* peut être une séquence
   ou un itérable.

   La médiane haute est toujours une valeur représentée dans les
   données. Lorsque le nombre d'observations est impair, la valeur du
   milieu est renvoyée. Sinon, la plus grande des deux valeurs du
   milieu est renvoyée.

      >>> median_high([1, 3, 5])
      3
      >>> median_high([1, 3, 5, 7])
      5

   Utilisez la médiane haute lorsque vos données sont discrètes et que
   vous préférez que la médiane soit une valeur représentée dans vos
   observations plutôt que le résultat d'une interpolation.

statistics.median_grouped(data, interval=1)

   Renvoie la médiane de données réelles groupées, calculée comme le
   50^e percentile (avec interpolation). Lève une erreur
   "StatisticsError" si *data* est vide. *data* peut être une séquence
   ou un itérable.

      >>> median_grouped([52, 52, 53, 54])
      52.5

   Dans l'exemple ci-dessous, les valeurs sont arrondies de sorte que
   chaque valeur représente le milieu d'un groupe. Par exemple 1 est
   le milieu du groupe 0,5 - 1, 2 est le milieu du groupe 1,5 - 2,5, 3
   est le milieu de 2,5 - 3,5, etc. Compte-tenu des valeurs ci-
   dessous, la valeur centrale se situe quelque part dans le groupe
   3,5 - 4,5 et est estimée par interpolation :

      >>> median_grouped([1, 2, 2, 3, 4, 4, 4, 4, 4, 5])
      3.7

   L'argument optionnel *interval* représente la largeur de
   l'intervalle des groupes (par défaut, 1). Changer l'intervalle des
   groupes change bien sûr l'interpolation :

      >>> median_grouped([1, 3, 3, 5, 7], interval=1)
      3.25
      >>> median_grouped([1, 3, 3, 5, 7], interval=2)
      3.5

   Cette fonction ne vérifie pas que les valeurs sont bien séparées
   d'au moins une fois *interval*.

   **CPython implementation detail:** Sous certaines conditions,
   "median_grouped()" peut convertir les valeurs en nombres à virgule
   flottante. Ce comportement est susceptible de changer dans le
   futur.

   Voir aussi:

     * *Statistics for the Behavioral Sciences*, Frederick J Gravetter
       et Larry B Wallnau (8^e édition, ouvrage en anglais).

     * La fonction SSMEDIAN du tableur Gnome Gnumeric ainsi que cette
       discussion.

statistics.mode(data)

   Renvoie la valeur la plus représentée dans la collection *data*
   (discrète ou nominale). Ce mode, lorsqu'il existe, est la valeur la
   plus représentative des données et est une mesure de la tendance
   centrale.

   S'il existe plusieurs modes avec la même fréquence, cette fonction
   renvoie le premier qui a été rencontré dans *data*. Utilisez
   "min(multimode(data))" ou "max(multimode(data))" si vous désirez le
   plus petit mode ou le plus grand mode. Lève une erreur
   "StatisticsError" si *data* est vide.

   "mode" suppose que les données sont discrètes et renvoie une seule
   valeur. Il s'agit de la définition usuelle du mode telle
   qu'enseignée dans à l'école :

      >>> mode([1, 1, 2, 3, 3, 3, 3, 4])
      3

   Le mode a la particularité d'être la seule statistique de ce module
   à pouvoir être calculée sur des données nominales (non numériques)
   :

      >>> mode(["red", "blue", "blue", "red", "green", "red", "red"])
      'red'

   Modifié dans la version 3.8: Gère désormais des jeux de données
   avec plusieurs modes en renvoyant le premier mode rencontré.
   Précédemment, une erreur "StatisticsError" était levée si plusieurs
   modes étaient trouvés.

statistics.multimode(data)

   Renvoie une liste des valeurs les plus fréquentes en suivant leur
   ordre d'apparition dans *data*. Renvoie plusieurs résultats s'il y
   a plusieurs modes ou une liste vide si *data* est vide :

      >>> multimode('aabbbbccddddeeffffgg')
      ['b', 'd', 'f']
      >>> multimode('')
      []

   Nouveau dans la version 3.8.

statistics.pstdev(data, mu=None)

   Renvoie l'écart-type de la population (racine carrée de la variance
   de la population). Voir "pvariance()" pour les arguments et
   d'autres précisions.

      >>> pstdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])
      0.986893273527251

statistics.pvariance(data, mu=None)

   Renvoie la variance de la population *data*, une séquence non-vide
   ou un itérable de valeurs réelles. La variance, ou moment de second
   ordre, est une mesure de la variabilité (ou dispersion) des
   données. Une variance élevée indique une large dispersion des
   valeurs ; une faible variance indique que les valeurs sont
   resserrées autour de la moyenne.

   Si le second argument optionnel *mu* est n'est pas spécifié ou est
   "None" (par défaut), il est remplacé automatiquement par la moyenne
   arithmétique. Cet argument correspond en général à la moyenne de
   *data*. En le spécifiant autrement, cela permet de calculer le
   moment de second ordre autour d'un point qui n'est pas la moyenne.

   Utilisez cette fonction pour calculer la variance sur une
   population complète. Pour estimer la variance à partir d'un
   échantillon, utilisez plutôt "variance()" à la place.

   Lève une erreur "StatisticsError" si *data* est vide.

   Exemples :

      >>> data = [0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25]
      >>> pvariance(data)
      1.25

   Si vous connaissez la moyenne de vos données, il est possible de la
   passer comme argument optionnel *mu* lors de l'appel de fonction
   pour éviter de la calculer une nouvelle fois :

      >>> mu = mean(data)
      >>> pvariance(data, mu)
      1.25

   La fonction gère les nombres décimaux et les fractions :

      >>> from decimal import Decimal as D
      >>> pvariance([D("27.5"), D("30.25"), D("30.25"), D("34.5"), D("41.75")])
      Decimal('24.815')

      >>> from fractions import Fraction as F
      >>> pvariance([F(1, 4), F(5, 4), F(1, 2)])
      Fraction(13, 72)

   Note:

     Cette fonction renvoie la variance de la population σ²
     lorsqu'elle est appliquée sur la population entière. Si elle est
     appliquée seulement sur un échantillon, le résultat est alors la
     variance de l'échantillon s² ou variance à N degrés de liberté.Si
     vous connaissez d'avance la vraie moyenne de la population μ,
     vous pouvez utiliser cette fonction pour calculer la variance de
     l'échantillon sachant la moyenne de la population en la passante
     comme second argument. En supposant que les observations sont
     issues d'un tirage aléatoire uniforme dans la population, le
     résultat sera une estimation non biaisée de la variance de la
     population.

statistics.stdev(data, xbar=None)

   Renvoie l'écart-type de l'échantillon (racine carrée de la variance
   de l'échantillon). Voir "variance()" pour les arguments et plus de
   détails.

      >>> stdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])
      1.0810874155219827

statistics.variance(data, xbar=None)

   Renvoie la variance de l'échantillon *data*, un itérable d'au moins
   deux valeurs réelles. La variance, ou moment de second ordre, est
   une mesure de la variabilité (ou dispersion) des données. Une
   variance élevée indique que les données sont très dispersées ; une
   variance faible indique que les valeurs sont resserrées autour de
   la moyenne.

   Si le second argument optionnel *xbar* est spécifié, celui-ci doit
   correspondre à la moyenne de *data*. S'il n'est pas spécifié ou
   "None" (par défaut), la moyenne est automatiquement calculée.

   Utilisez cette fonction lorsque vos données forment un échantillon
   d'une population plus grande. Pour calculer la variance d'une
   population complète, utilisez "pvariance()".

   Lève une erreur "StatisticsError" si *data* contient moins de deux
   éléments.

   Exemples :

      >>> data = [2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5]
      >>> variance(data)
      1.3720238095238095

   Si vous connaissez la moyenne de vos données, il est possible de la
   passer comme argument optionnel *xbar* lors de l'appel de fonction
   pour éviter de la calculer une nouvelle fois :

      >>> m = mean(data)
      >>> variance(data, m)
      1.3720238095238095

   Cette fonction ne vérifie pas que la valeur passée dans l'argument
   *xbar* correspond bien à la moyenne. Utiliser des valeurs
   arbitraires pour *xbar* produit des résultats impossibles ou
   incorrects.

   La fonction gère les nombres décimaux et les fractions :

      >>> from decimal import Decimal as D
      >>> variance([D("27.5"), D("30.25"), D("30.25"), D("34.5"), D("41.75")])
      Decimal('31.01875')

      >>> from fractions import Fraction as F
      >>> variance([F(1, 6), F(1, 2), F(5, 3)])
      Fraction(67, 108)

   Note:

     Cela correspond à la variance s² de l'échantillon avec correction
     de Bessel (ou variance à N-1 degrés de liberté). En supposant que
     les observations sont représentatives de la population
     (c'est-à-dire indépendantes et identiquement distribuées), alors
     le résultat est une estimation non biaisée de la variance.Si vous
     connaissez d'avance la vraie moyenne μ de la population, vous
     devriez la passer à "pvariance()" comme paramètre *mu* pour
     obtenir la variance de l'échantillon.

statistics.quantiles(data, *, n=4, method='exclusive')

   Divise *data* en *n* intervalles réels de même probabilité. Renvoie
   une liste de "n - 1" valeurs délimitant les intervalles (les
   quantiles).

   Utilisez "n = 4" pour obtenir les quartiles (le défaut), "n = 10"
   pour obtenir les déciles et "n = 100" pour obtenir les centiles (ce
   qui produit 99 valeurs qui séparent *data* en 100 groupes de même
   taille). Lève une erreur "StatisticsError" si *n* est strictement
   inférieur à 1.

   *data* peut être n'importe quel itérable contenant les valeurs de
   l'échantillon. Pour que les résultats aient un sens, le nombre
   d'observations dans l'échantillon *data* doit être plus grand que
   *n*. Lève une erreur "StatisticsError" s'il n'y a pas au moins deux
   observations.

   Les quantiles sont linéairement interpolées à partir des deux
   valeurs les plus proches dans l'échantillon. Par exemple, si un
   quantile se situe à un tiers de la distance entre les deux valeurs
   de l'échantillon "100" et "112", le quantile vaudra "104".

   L'argument *method* indique la méthode à utiliser pour calculer les
   quantiles et peut être modifié pour spécifier s'il faut inclure ou
   exclure les valeurs basses et hautes de *data* de la population.

   La valeur par défaut pour *method* est ""exclusive"" et est
   applicable pour des données échantillonnées dans une population
   dont une des valeurs extrêmes peut être plus grande (respectivement
   plus petite) que le maximum (respectivement le minimum) des valeurs
   de l'échantillon. La proportion de la population se situant en-
   dessous du i^e de *m* valeurs ordonnées est calculée par la formule
   "i / (m + 1)". Par exemple, en supposant 9 valeurs dans
   l'échantillon, cette méthode les ordonne et leur associe les
   quantiles suivants : 10%, 20%, 30%, 40%, 50%, 60%, 70%, 80%, 90%.

   En utilisant ""inclusive"" comme valeur du paramètre *method*, on
   suppose que *data* correspond soit à une population entière, soit
   que les valeurs extrêmes de la population sont représentées dans
   l'échantillon. Le minimum de *data* est alors considéré comme 0^e
   centile et le maximum comme 100^e centile. La proportion de la
   population se situant sous la i^e valeur de *m* valeurs ordonnées
   est calculée par la formule "(i - 1)/(m - 1)". En supposant que
   l'on a 11 valeurs dans l'échantillon, cette méthode les ordonne et
   leur associe les quantiles suivants : 0%, 10%, 20%, 30%, 40%, 50%,
   60%, 70%, 80%, 90%, 100%.

      # Decile cut points for empirically sampled data
      >>> data = [105, 129, 87, 86, 111, 111, 89, 81, 108, 92, 110,
      ...         100, 75, 105, 103, 109, 76, 119, 99, 91, 103, 129,
      ...         106, 101, 84, 111, 74, 87, 86, 103, 103, 106, 86,
      ...         111, 75, 87, 102, 121, 111, 88, 89, 101, 106, 95,
      ...         103, 107, 101, 81, 109, 104]
      >>> [round(q, 1) for q in quantiles(data, n=10)]
      [81.0, 86.2, 89.0, 99.4, 102.5, 103.6, 106.0, 109.8, 111.0]

   Nouveau dans la version 3.8.


Exceptions
==========

Une seule exception est définie :

exception statistics.StatisticsError

   Sous-classe de "ValueError" pour les exceptions liées aux
   statistiques.


Objets "NormalDist"
===================

"NormalDist" est un outil permettant de créer et manipuler des lois
normales de variables aléatoires. Cette classe gère la moyenne et l
'écart-type d'un ensemble d'observations comme une seule entité.

Les lois normales apparaissent dans de très nombreuses applications
des statistiques. Leur ubiquité découle du *théorème central limite
<https://fr.wikipedia.org/wiki/Th%C3%A9or%C3%A8me_central_limite>*.

class statistics.NormalDist(mu=0.0, sigma=1.0)

   Renvoie un nouvel objet *NormalDist* où *mu* représente la moyenne
   arithmétique et *sigma* l'écart-type.

   Lève une erreur "StatisticsError" si *sigma* est négatif.

   mean

      Attribut en lecture seule correspondant à la moyenne
      arithmétique d'une loi normale.

   median

      Attribut en lecture seule correspondant à la médiane d'une loi
      normale.

   mode

      Attribut en lecture seule correspondant au mode d'une loi
      normale.

   stdev

      Attribut en lecture seule correspondant à l'écart-type d'une loi
      normale.

   variance

      Attribut en lecture seule correspondant à la variance d'une loi
      normale. La variance est égale au carré de l'écart-type.

   classmethod from_samples(data)

      Crée une instance de loi normale de paramètres *mu* et *sigma*
      estimés à partir de *data* en utilisant "fmean()" et "stdev()".

      *data* peut être n'importe quel *iterable* de valeurs pouvant
      être converties en "float". Lève une erreur "StatisticsError" si
      *data* ne contient pas au moins deux éléments car il faut au
      moins un point pour estimer la moyenne et deux points pour
      estimer la variance.

   samples(n, *, seed=None)

      Génère *n* valeurs aléatoires suivant une loi normale de moyenne
      et écart-type connus. Renvoie une "list" de "float".

      Si *seed* est spécifié, sa valeur est utilisée pour initialiser
      une nouvelle instance du générateur de nombres aléatoires. Cela
      permet de produire des résultats reproductibles même dans un
      contexte de parallélisme par fils d'exécution.

   pdf(x)

      Calcule la vraisemblance qu'une variable aléatoire *X* soit
      proche de la valeur *x* à partir de la fonction de densité.
      Mathématiquement, cela correspond à la limite de la fraction
      "P(x <= X < x + dx) / dx" lorsque "dx" tend vers zéro.

      La vraisemblance relative est calculée comme la probabilité
      qu'une observation appartienne à un intervalle étroit divisée
      par la largeur de l'intervalle (d'où l'appellation « densité »).
      La vraisemblance étant relative aux autres points, sa valeur
      peut être supérieure à 1,0.

   cdf(x)

      Calcule la probabilité qu'une variable aléatoire *X* soit
      inférieure ou égale à *x* à partir de la fonction de
      répartition. Mathématiquement, cela correspond à "P(X <= x)".

   inv_cdf(p)

      Calcule l'inverse de la fonction de répartition, c'est-à-dire la
      fonction quantile. Mathématiquement, il s'agit de "x : P(X <= x)
      = p".

      Détermine la valeur *x* de la variable aléatoire *X* telle que
      la probabilité que la variable soit inférieure ou égale à cette
      valeur *x* est égale à *p*.

   overlap(other)

      Mesure le recouvrement entre deux lois normales. Renvoie une
      valeur réelle entre 0 et 1 indiquant l'aire du recouvrement de
      deux densités de probabilité.

   quantiles(n=4)

      Divise la loi normale entre *n* intervalles réels équiprobables.
      Renvoie une liste de "(n - 1)" quantiles séparant les
      intervalles.

      Utilisez "n = 4" pour obtenir les quartiles (le défaut), "n =
      10" pour obtenir les déciles et "n = 100" pour obtenir les
      centiles (ce qui produit 99 valeurs qui séparent *data* en 100
      groupes de même taille).

   Les instances de la classe "NormalDist" gèrent l'addition, la
   soustraction, la multiplication et la division par une constante.
   Ces opérations peuvent être utilisées pour la translation ou la
   mise à l'échelle, par exemple :

      >>> temperature_february = NormalDist(5, 2.5)             # Celsius
      >>> temperature_february * (9/5) + 32                     # Fahrenheit
      NormalDist(mu=41.0, sigma=4.5)

   Diviser une constante par une instance de "NormalDist" n'est pas
   pris en charge car le résultat ne serait pas une loi normale.

   Étant donné que les lois normales sont issues des propriétés
   additives de variables indépendantes, il est possible d'ajouter ou
   de soustraite deux variables normales indépendantes représentées
   par des instances de "NormalDist". Par exemple :

      >>> birth_weights = NormalDist.from_samples([2.5, 3.1, 2.1, 2.4, 2.7, 3.5])
      >>> drug_effects = NormalDist(0.4, 0.15)
      >>> combined = birth_weights + drug_effects
      >>> round(combined.mean, 1)
      3.1
      >>> round(combined.stdev, 1)
      0.5

   Nouveau dans la version 3.8.


Exemples d'utilisation de "NormalDist"
--------------------------------------

"NormalDist" permet de résoudre aisément des problèmes probabilistes
classiques.

Par exemple, sachant que les scores aux examens SAT suivent une loi
normale de moyenne 1060 et d'écart-type 195, déterminer le pourcentage
d'étudiants dont les scores se situent entre 1100 et 1200, arrondi à
l'entier le plus proche :

   >>> sat = NormalDist(1060, 195)
   >>> fraction = sat.cdf(1200 + 0.5) - sat.cdf(1100 - 0.5)
   >>> round(fraction * 100.0, 1)
   18.4

Déterminer les quartiles et les déciles des scores SAT :

   >>> list(map(round, sat.quantiles()))
   [928, 1060, 1192]
   >>> list(map(round, sat.quantiles(n=10)))
   [810, 896, 958, 1011, 1060, 1109, 1162, 1224, 1310]

"NormalDist" peut générer des observations pour une simulation
utilisant la méthode de Monte-Carlo afin d'estimer la distribution
d'un modèle difficile à résoudre analytiquement :

   >>> def model(x, y, z):
   ...     return (3*x + 7*x*y - 5*y) / (11 * z)
   ...
   >>> n = 100_000
   >>> X = NormalDist(10, 2.5).samples(n, seed=3652260728)
   >>> Y = NormalDist(15, 1.75).samples(n, seed=4582495471)
   >>> Z = NormalDist(50, 1.25).samples(n, seed=6582483453)
   >>> quantiles(map(model, X, Y, Z))       
   [1.4591308524824727, 1.8035946855390597, 2.175091447274739]

Les lois normales peuvent être utilisées pour approcher des lois
binomiales lorsque le nombre d'observations est grand et que la
probabilité de succès de l'épreuve est proche de 50%.

Par exemple, 750 personnes assistent à une conférence sur le logiciel
libre. Il y a deux salles pouvant chacune accueillir 500 personnes.
Dans la première salle a lieu une présentation sur Python, dans
l'autre une présentation à propos de Ruby. Lors des conférences
passées, 65% des personnes ont préféré écouter les présentations sur
Python. En supposant que les préférences de la population n'ont pas
changé, quelle est la probabilité que la salle Python reste en-dessous
de sa capacité d'accueil ?

   >>> n = 750             # Sample size
   >>> p = 0.65            # Preference for Python
   >>> q = 1.0 - p         # Preference for Ruby
   >>> k = 500             # Room capacity

   >>> # Approximation using the cumulative normal distribution
   >>> from math import sqrt
   >>> round(NormalDist(mu=n*p, sigma=sqrt(n*p*q)).cdf(k + 0.5), 4)
   0.8402

   >>> # Solution using the cumulative binomial distribution
   >>> from math import comb, fsum
   >>> round(fsum(comb(n, r) * p**r * q**(n-r) for r in range(k+1)), 4)
   0.8402

   >>> # Approximation using a simulation
   >>> from random import seed, choices
   >>> seed(8675309)
   >>> def trial():
   ...     return choices(('Python', 'Ruby'), (p, q), k=n).count('Python')
   >>> mean(trial() <= k for i in range(10_000))
   0.8398

Les lois normales interviennent souvent en apprentissage automatique.

Wikipédia détaille un bon exemple de classification naïve bayésienne.
L'objectif est de prédire le sexe d'une personne à partir de
caractéristiques physiques qui suivent une loi normale, telles que la
hauteur, le poids et la pointure.

Nous avons à notre disposition un jeu de données d'apprentissage
contenant les mesures de huit personnes. On suppose que ces mesures
suivent une loi normale. Nous pouvons donc synthétiser les données à
l'aide de "NormalDist" :

   >>> height_male = NormalDist.from_samples([6, 5.92, 5.58, 5.92])
   >>> height_female = NormalDist.from_samples([5, 5.5, 5.42, 5.75])
   >>> weight_male = NormalDist.from_samples([180, 190, 170, 165])
   >>> weight_female = NormalDist.from_samples([100, 150, 130, 150])
   >>> foot_size_male = NormalDist.from_samples([12, 11, 12, 10])
   >>> foot_size_female = NormalDist.from_samples([6, 8, 7, 9])

Ensuite, nous rencontrons un nouvel individu dont nous connaissons les
proportions mais pas le sexe :

   >>> ht = 6.0        # height
   >>> wt = 130        # weight
   >>> fs = 8          # foot size

En partant d'une probabilité a priori de 50% d'être un homme ou une
femme, nous calculons la probabilité a posteriori comme le produit de
la probabilité antérieure et de la vraisemblance des différentes
mesures étant donné le sexe :

   >>> prior_male = 0.5
   >>> prior_female = 0.5
   >>> posterior_male = (prior_male * height_male.pdf(ht) *
   ...                   weight_male.pdf(wt) * foot_size_male.pdf(fs))

   >>> posterior_female = (prior_female * height_female.pdf(ht) *
   ...                     weight_female.pdf(wt) * foot_size_female.pdf(fs))

La prédiction finale est celle qui a la plus grande probabilité a
posteriori. Cette approche est appelée maximum a posteriori ou MAP :

   >>> 'male' if posterior_male > posterior_female else 'female'
   'female'
