¿Cómo calcular la probabilidad en una distribución normal dada la media y la desviación estándar?

91

¿Cómo calcular la probabilidad en una distribución normal dada la media, std en Python? Siempre puedo codificar explícitamente mi propia función de acuerdo con la definición como lo hizo el OP en esta pregunta: Cálculo de la probabilidad de una variable aleatoria en una distribución en Python

Solo preguntarse si hay una llamada a la función de biblioteca le permitirá hacer esto. En mi imaginación, le gustaría esto:

nd = NormalDistribution(mu=100, std=12)
p = nd.prob(98)

Hay una pregunta similar en Perl: ¿Cómo puedo calcular la probabilidad en un punto dada una distribución normal en Perl? . Pero no vi uno en Python.

Numpytiene una random.normalfunción, pero es como muestrear, no exactamente lo que quiero.

clwen
fuente

Respuestas:

129

Hay uno en scipy.stats :

>>> import scipy.stats
>>> scipy.stats.norm(0, 1)
<scipy.stats.distributions.rv_frozen object at 0x928352c>
>>> scipy.stats.norm(0, 1).pdf(0)
0.3989422804014327
>>> scipy.stats.norm(0, 1).cdf(0)
0.5
>>> scipy.stats.norm(100, 12)
<scipy.stats.distributions.rv_frozen object at 0x928352c>
>>> scipy.stats.norm(100, 12).pdf(98)
0.032786643008494994
>>> scipy.stats.norm(100, 12).cdf(98)
0.43381616738909634
>>> scipy.stats.norm(100, 12).cdf(100)
0.5

[Una cosa a tener en cuenta, solo un consejo, es que el paso de parámetros es un poco amplio. Debido a la forma en que está configurado el código, si escribe accidentalmente en scipy.stats.norm(mean=100, std=12)lugar de scipy.stats.norm(100, 12)o scipy.stats.norm(loc=100, scale=12), lo aceptará, pero descartará silenciosamente esos argumentos de palabras clave adicionales y le dará el valor predeterminado (0,1).]

DSM
fuente
3
¿Cómo obtendrías probabilidades de rangos? ¿De 98 a 102?
León
2
@DSM: En su ejemplo anterior, cuando dice scipy.stats.norm(100, 12).pdf(98), ¿eso significa la probabilidad de obtener 98 en una distribución con mean 100 y stddev 12es 0.032?
Srivatsan
14
@ThePredator: no, la probabilidad de obtener 98 en una distribución normal con media 100 y stddev 12 es cero. :-) La densidad de probabilidad es 0.032.
DSM
En ese caso, la densidad de probabilidad significa el valor y, dado el valor x 1,42 para la distribución normal. cdf significa lo que llamamos el área bajo la curva.
trituración
5
@Leon, ahí es rv.cdf(102) - rv.cdf(98)donde rv = scipy.stats.norm(100, 12).
fuglede
46

Scipy.stats es un gran módulo. Solo para ofrecer otro enfoque, puede calcularlo directamente usando

import math
def normpdf(x, mean, sd):
    var = float(sd)**2
    denom = (2*math.pi*var)**.5
    num = math.exp(-(float(x)-float(mean))**2/(2*var))
    return num/denom

Esto usa la fórmula que se encuentra aquí: http://en.wikipedia.org/wiki/Normal_distribution#Probability_density_function

Probar:

>>> normpdf(7,5,5)  
0.07365402806066466
>>> norm(5,5).pdf(7)
0.073654028060664664
jiminy_crist
fuente
Oye, esta es una respuesta realmente agradable. ¿Le importaría proporcionar una explicación paso a paso, tal vez?
Llamageddon
Este método necesita menos tiempo de cálculo que scipy
mkm
Pero scipy puede manejar matrices de medias, stdevs y muestras: mean = [5, 10, 20] stddev = [20, 30, 40] para x en ([5, 10, 20], [10, 20, 40], [15, 30, 50],): prob = scipy.stats.norm (mean, stddev) .cdf (x) print (f'prob = {prob} ') salidas: prob = [0.5 0.5 0.5] prob = [ 0.59870633 0.63055866 0.69146246] prob = [0.69146246 0.74750746 0.77337265]
John Deighan
16

Aquí hay más información . Primero, se trata de una distribución congelada (congelada en este caso significa que sus parámetros se establecen en valores específicos). Para crear una distribución congelada:

import scipy.stats
scipy.stats.norm(loc=100, scale=12)
#where loc is the mean and scale is the std dev
#if you wish to pull out a random number from your distribution
scipy.stats.norm.rvs(loc=100, scale=12)

#To find the probability that the variable has a value LESS than or equal
#let's say 113, you'd use CDF cumulative Density Function
scipy.stats.norm.cdf(113,100,12)
Output: 0.86066975255037792
#or 86.07% probability

#To find the probability that the variable has a value GREATER than or
#equal to let's say 125, you'd use SF Survival Function 
scipy.stats.norm.sf(125,100,12)
Output: 0.018610425189886332
#or 1.86%

#To find the variate for which the probability is given, let's say the 
#value which needed to provide a 98% probability, you'd use the 
#PPF Percent Point Function
scipy.stats.norm.ppf(.98,100,12)
Output: 124.64498692758187
J. Khoury
fuente
No puedo agradecer lo suficiente a quien escribió esta respuesta. Estaba buscando por todas partes para resolver esto, pero no pude encontrarlo. Y agregar los comentarios con el código realmente me ayudó a comprender lo que está sucediendo. Muchas gracias.
bhola prasad
Solo quiero hacer una pregunta, ¿cómo calcular estas probabilidades cuando los datos no se distribuyen normalmente? ¿Qué tengo que hacer en este caso?
bhola prasad
12

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

Se puede usar para obtener la función de densidad de probabilidad ( pdf- probabilidad de que una muestra aleatoria X esté cerca del valor dado x) para una media ( mu) y una desviación estándar ( sigma) dadas :

from statistics import NormalDist

NormalDist(mu=100, sigma=12).pdf(98)
# 0.032786643008494994

También tenga en cuenta que el NormalDistobjeto también proporciona la función de distribución acumulativa ( cdf- probabilidad de que una muestra aleatoria X sea menor o igual ax):

NormalDist(mu=100, sigma=12).cdf(98)
# 0.43381616738909634
Xavier Guihot
fuente
4

En caso de que desee encontrar el área entre 2 valores de x mean = 1; desviación estándar = 2; la probabilidad de x entre [0.5,2]

import scipy.stats
scipy.stats.norm(1, 2).cdf(2) - scipy.stats.norm(1,2).cdf(0.5)
Prashanth
fuente
3

La fórmula citada de wikipedia mencionada en las respuestas no se puede utilizar para calcular probabilidades normales. Tendría que escribir una función de aproximación de integración numérica usando esa fórmula para calcular la probabilidad.

Esa fórmula calcula el valor de la función de densidad de probabilidad. Dado que la distribución normal es continua, debes calcular una integral para obtener probabilidades. El sitio de wikipedia menciona el CDF, que no tiene un formulario cerrado para la distribución normal.

usuario2724943
fuente
3
Gracias por tu contribución, aunque encajaría mejor como comentario a la respuesta a la que te refieres: si entiendo bien, realmente no estás respondiendo a la pregunta original. De esta forma, todos verán a primera vista de qué estás hablando.
Pierre Prinetti
1

Escribí este programa para hacer los cálculos por ti. Simplemente ingrese las estadísticas resumidas. No es necesario proporcionar una matriz:

Prueba Z de una muestra para una proporción de población:

Para hacer esto para la media en lugar de la proporción, cambie la fórmula para z en consecuencia

EDITAR:
Aquí está el contenido del enlace:

import scipy.stats as stats
import math

def one_sample_ztest_pop_proportion(tail, p, pbar, n, alpha):
    #Calculate test stat

    sigma = math.sqrt((p*(1-p))/(n))
    z = round((pbar - p) / sigma, 2)

    if tail == 'lower':
        pval = round(stats.norm(p, sigma).cdf(pbar),4)
        print("Results for a lower tailed z-test: ")


    elif tail == 'upper':
        pval = round(1 - stats.norm(p, sigma).cdf(pbar),4)
        print("Results for an upper tailed z-test: ")


    elif tail == 'two':
        pval = round(stats.norm(p, sigma).cdf(pbar)*2,4)
        print("Results for a two tailed z-test: ")


    #Print test results
    print("Test statistic = {}".format(z))   
    print("P-value = {}".format(pval))
    print("Confidence = {}".format(alpha))

    #Compare p-value to confidence level
    if pval <= alpha:
        print("{} <=  {}. Reject the null hypothesis.".format(pval, alpha))
    else:
        print("{} > {}. Do not reject the null hypothesis.".format(pval, alpha))


#one_sample_ztest_pop_proportion('upper', .20, .25, 400, .05)

#one_sample_ztest_pop_proportion('two', .64, .52, 100, .05)
derrik bosse
fuente
2
Si bien el enlace puede proporcionar una respuesta valiosa, SO pide a los usuarios que publiquen su código aquí en SO Los enlaces son útiles como referencia, pero tienden a romperse después de un tiempo, lo que hace que las soluciones sean inaccesibles para futuros visitantes.
Mr. T