Comment calculer la distribution normale cumulée?

100

Je recherche une fonction en Numpy ou Scipy (ou toute bibliothèque Python rigoureuse) qui me donnera la fonction de distribution normale cumulative en Python.

Martineau
la source

Réponses:

125

Voici un exemple:

>>> from scipy.stats import norm
>>> norm.cdf(1.96)
0.9750021048517795
>>> norm.cdf(-1.96)
0.024997895148220435

En d'autres termes, environ 95% de l'intervalle normal standard se situe à l'intérieur de deux écarts types, centrés sur une moyenne standard de zéro.

Si vous avez besoin du CDF inverse:

>>> norm.ppf(norm.cdf(1.96))
array(1.9599999999999991)
Alex Reynolds
la source
9
En outre, vous pouvez spécifier la moyenne (loc) et la variance (échelle) en tant que paramètres. par exemple, d = norme (loc = 10,0, échelle = 2,0); d.cdf (12,0); Détails ici: docs.scipy.org/doc/scipy-0.14.0/reference/generated/…
Irvan
6
@Irvan, le paramètre d'échelle est en fait l'écart type, PAS la variance.
qkhhly
2
Pourquoi scipy les nomme-t-il locet scale? J'ai utilisé le help(norm.ppf)mais alors qu'est-ce que diable sont locet scale- j'ai besoin d'aide pour l'aide ..
javadba
2
@javadba - l'emplacement et l'échelle sont des termes plus généraux dans les statistiques qui sont utilisés pour paramétrer un large éventail de distributions. Pour la distribution normale, ils s'alignent avec la moyenne et le sd, mais pas pour les autres distributions.
Michael Ohlrogge
1
@MichaelOhlrogge. THX! Voici une page du NIST expliquant plus en détail itl.nist.gov/div898/handbook/eda/section3/eda364.htm
javadba
40

Il est peut-être trop tard pour répondre à la question, mais comme Google conduit toujours les gens ici, je décide d'écrire ma solution ici.

Autrement dit, depuis Python 2.7, la mathbibliothèque a intégré la fonction d'erreurmath.erf(x)

La erf()fonction peut être utilisée pour calculer des fonctions statistiques traditionnelles telles que la distribution normale standard cumulative:

from math import *
def phi(x):
    #'Cumulative distribution function for the standard normal distribution'
    return (1.0 + erf(x / sqrt(2.0))) / 2.0

Réf:

https://docs.python.org/2/library/math.html

https://docs.python.org/3/library/math.html

Comment la fonction d'erreur et la fonction de distribution normale standard sont-elles liées?

WTIFS
la source
3
C'était exactement ce que je cherchais. Si quelqu'un d'autre que moi se demande comment cela peut être utilisé pour calculer "le pourcentage de données qui se trouve dans la distribution standard", eh bien: 1 - (1 - phi (1)) * 2 = 0,6827 ("68% des données dans 1 standard déviation ")
Hannes Landeholm
1
Pour une distribution normale générale, ce serait le cas def phi(x, mu, sigma): return (1 + erf((x - mu) / sigma / sqrt(2))) / 2.
Bernhard Barker
18

Adapté d'ici http://mail.python.org/pipermail/python-list/2000-June/039873.html

from math import *
def erfcc(x):
    """Complementary error function."""
    z = abs(x)
    t = 1. / (1. + 0.5*z)
    r = t * exp(-z*z-1.26551223+t*(1.00002368+t*(.37409196+
        t*(.09678418+t*(-.18628806+t*(.27886807+
        t*(-1.13520398+t*(1.48851587+t*(-.82215223+
        t*.17087277)))))))))
    if (x >= 0.):
        return r
    else:
        return 2. - r

def ncdf(x):
    return 1. - 0.5*erfcc(x/(2**0.5))
Inconnue
la source
3
Puisque la bibliothèque std implémente math.erf (), il n'y a pas besoin d'une implémentation sep.
Marc
Je n'ai pas pu trouver de réponse, d'où viennent ces chiffres?
TmSmth
17

Au départ Python 3.8, la bibliothèque standard fournit l' NormalDistobjet dans le cadre du statisticsmodule.

Il peut être utilisé pour obtenir la fonction de distribution cumulative ( cdf- probabilité qu'un échantillon aléatoire X soit inférieur ou égal à x) pour une moyenne ( mu) et un écart type ( sigma) donnés :

from statistics import NormalDist

NormalDist(mu=0, sigma=1).cdf(1.96)
# 0.9750021048517796

Ce qui peut être simplifié pour la distribution normale standard ( mu = 0et sigma = 1):

NormalDist().cdf(1.96)
# 0.9750021048517796

NormalDist().cdf(-1.96)
# 0.024997895148220428
Xavier Guihot
la source
15

Pour construire sur l'exemple de Unknown, l'équivalent Python de la fonction normdist () implémentée dans de nombreuses bibliothèques serait:

def normcdf(x, mu, sigma):
    t = x-mu;
    y = 0.5*erfcc(-t/(sigma*sqrt(2.0)));
    if y>1.0:
        y = 1.0;
    return y

def normpdf(x, mu, sigma):
    u = (x-mu)/abs(sigma)
    y = (1/(sqrt(2*pi)*abs(sigma)))*exp(-u*u/2)
    return y

def normdist(x, mu, sigma, f):
    if f:
        y = normcdf(x,mu,sigma)
    else:
        y = normpdf(x,mu,sigma)
    return y
Cerin
la source
9

La réponse d'Alex vous montre une solution pour la distribution normale standard (moyenne = 0, écart-type = 1). Si vous avez une distribution normale avec meanet std(qui est sqr(var)) et que vous souhaitez calculer:

from scipy.stats import norm

# cdf(x < val)
print norm.cdf(val, m, s)

# cdf(x > val)
print 1 - norm.cdf(val, m, s)

# cdf(v1 < x < v2)
print norm.cdf(v2, m, s) - norm.cdf(v1, m, s)

En savoir plus sur cdf ici et l'implémentation scipy de la distribution normale avec de nombreuses formules ici .

Salvador Dali
la source
2

Prise d'en haut:

from scipy.stats import norm
>>> norm.cdf(1.96)
0.9750021048517795
>>> norm.cdf(-1.96)
0.024997895148220435

Pour un test bilatéral:

Import numpy as np
z = 1.96
p_value = 2 * norm.cdf(-np.abs(z))
0.04999579029644087
David Miller
la source
-9

Comme Google donne cette réponse pour la recherche netlogo pdf , voici la version netlogo du code python ci-dessus

    ;; Fonction de densité cumulative de distribution normale
    to-report normcdf [x mu sigma]
        laissez tx - mu
        soit y 0.5 * erfcc [- t / (sigma * sqrt 2.0)]
        if (y> 1.0) [set y 1.0]
        signaler y
    fin

    ;; Fonction de densité de probabilité de distribution normale
    to-report normpdf [x mu sigma]
        soit u = (x - mu) / abs sigma
        soit y = 1 / (sqrt [2 * pi] * abs sigma) * exp (- u * u / 2.0)
        signaler y
    fin

    ;; Fonction d'erreur complémentaire
    rapporter erfcc [x]
        laissez z abs x
        soit t 1,0 / (1,0 + 0,5 * z)
        soit rt * exp (- z * z -1.26551223 + t * (1.00002368 + t * (0.37409196 +
            t * (0,09678418 + t * (-0,18628806 + t * (0,27886807 +
            t * (-1,13520398 + t * (1,48851587 + t * (-0,82215223 +
            t * .17087277)))))))))
        ifelse (x> = 0) [rapport r] [rapport 2.0 - r]
    fin

platipodium
la source
6
La question concerne Python, pas NetLogo. Cette réponse ne devrait pas être ici. Et veuillez ne pas modifier la question pour changer sa signification.
entre
Je sais que ce n'est pas la méthode préférée, mais je suppose que c'est plus utile de cette façon car les gens sont dirigés vers cette page par google (actuellement ...)
platipodium