¿Cómo calcular la distribución normal acumulada?

99

Estoy buscando una función en Numpy o Scipy (o cualquier biblioteca Python rigurosa) que me dé la función de distribución normal acumulativa en Python.

martineau
fuente

Respuestas:

125

He aquí un ejemplo:

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

En otras palabras, aproximadamente el 95% del intervalo normal estándar se encuentra dentro de dos desviaciones estándar, centradas en una media estándar de cero.

Si necesita el CDF inverso:

>>> norm.ppf(norm.cdf(1.96))
array(1.9599999999999991)
Alex Reynolds
fuente
9
Además, puede especificar la media (loc) y la varianza (escala) como parámetros. por ejemplo, d = norma (loc = 10.0, escala = 2.0); d.cdf (12,0); Detalles aquí: docs.scipy.org/doc/scipy-0.14.0/reference/generated/…
Irvan
6
@Irvan, el parámetro de escala es en realidad la desviación estándar, NO la varianza.
qkhhly
2
¿Por qué scipy los nombra como locy scale? help(norm.ppf)locscale
Usé
2
@javadba: la ubicación y la escala son términos más generales en las estadísticas que se utilizan para parametrizar una amplia gama de distribuciones. Para la distribución normal, se alinean con la media y la sd, pero no así con otras distribuciones.
Michael Ohlrogge
1
@MichaelOhlrogge. ¡Gracias! Aquí hay una página del NIST que explica más itl.nist.gov/div898/handbook/eda/section3/eda364.htm
javadba
40

Puede que sea demasiado tarde para responder la pregunta, pero dado que Google todavía lleva a la gente aquí, decido escribir mi solución aquí.

Es decir, desde Python 2.7, la mathbiblioteca ha integrado la función de errormath.erf(x)

La erf()función se puede utilizar para calcular funciones estadísticas tradicionales como la distribución normal estándar acumulativa:

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

Árbitro:

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

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

¿Cómo se relacionan la función de error y la función de distribución normal estándar?

WTIFS
fuente
3
Esto era exactamente lo que estaba buscando. Si alguien más que yo se pregunta cómo se puede utilizar para calcular el "porcentaje de datos que se encuentran dentro de la distribución estándar", bueno: 1 - (1 - phi (1)) * 2 = 0,6827 ("68% de los datos dentro de 1 estándar desviación ")
Hannes Landeholm
1
Para una distribución normal general, lo sería def phi(x, mu, sigma): return (1 + erf((x - mu) / sigma / sqrt(2))) / 2.
Bernhard Barker
19

Adaptado de aquí 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))
Desconocido
fuente
3
Dado que std lib implementa math.erf (), no hay necesidad de una implementación sep.
Marc
No pude encontrar una respuesta, ¿de dónde provienen esos números?
TmSmth
15

Para construir sobre el ejemplo de Unknown, el equivalente en Python de la función normdist () implementada en muchas bibliotecas sería:

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
fuente
15

A partir Python 3.8, la biblioteca estándar proporciona el NormalDistobjeto como parte del statisticsmódulo.

Se puede utilizar para obtener la función de distribución acumulativa ( cdf- probabilidad de que una muestra aleatoria X sea menor o igual ax) para una media ( mu) y una desviación estándar ( sigma) dadas :

from statistics import NormalDist

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

Que se puede simplificar para la distribución normal estándar ( mu = 0y sigma = 1):

NormalDist().cdf(1.96)
# 0.9750021048517796

NormalDist().cdf(-1.96)
# 0.024997895148220428
Xavier Guihot
fuente
9

La respuesta de Alex le muestra una solución para la distribución normal estándar (media = 0, desviación estándar = 1). Si tiene una distribución normal con meany std(cuál es sqr(var)) y desea calcular:

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)

Lea más sobre cdf aquí y la implementación scipy de distribución normal con muchas fórmulas aquí .

Salvador Dalí
fuente
2

Tomado de arriba:

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

Para una prueba de dos colas:

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

Como Google da esta respuesta para la búsqueda netlogo pdf , aquí está la versión netlogo del código Python anterior

    ;; Función de densidad acumulativa de distribución normal
    para informar normcdf [x mu sigma]
        deja tx - mu
        sea ​​y 0.5 * erfcc [- t / (sigma * sqrt 2.0)]
        si (y> 1.0) [establecer y 1.0]
        informe y
    final

    ;; Función de densidad de probabilidad de distribución normal
    para informar normpdf [x mu sigma]
        sea ​​u = (x - mu) / abs sigma
        sea ​​y = 1 / (sqrt [2 * pi] * abs sigma) * exp (- u * u / 2.0)
        informe y
    final

    ;; Función de error complementaria
    para informar erfcc [x]
        sea ​​z abs x
        sea ​​t 1.0 / (1.0 + 0.5 * z)
        sea ​​rt * exp (- z * z -1.26551223 + t * (1.00002368 + t * (0.37409196 +
            t * (0.09678418 + t * (-0.18628806 + t * (.27886807 +
            t * (-1.13520398 + t * (1.48851587 + t * (-0.82215223 +
            t * .17087277)))))))))
        ifelse (x> = 0) [informe r] [informe 2.0 - r]
    final

platipodio
fuente
6
La pregunta es sobre Python, no sobre NetLogo. Esta respuesta no debería estar aquí. Y no edite la pregunta para cambiar su significado.
interjay
Soy consciente de que esta no es la forma preferida, pero supongo que es más útil de esta manera, ya que Google dirige a las personas a esta página (actualmente ...)
platipodium