Comment calculer la probabilité dans une distribution normale compte tenu de la moyenne et de l'écart type?


91

Comment calculer la probabilité dans une distribution normale donnée moyenne, std en Python? Je peux toujours coder explicitement ma propre fonction selon la définition comme l'a fait l'OP dans cette question: Calcul de la probabilité d'une variable aléatoire dans une distribution en Python

Se demander s'il y a un appel de fonction de bibliothèque vous permettra de le faire. Dans mon imagination, cela aimerait:

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

Il y a une question similaire en Perl: comment puis-je calculer la probabilité en un point donné une distribution normale en Perl? . Mais je n'en ai pas vu en Python.

Numpya une random.normalfonction, mais c'est comme l'échantillonnage, pas exactement ce que je veux.

Réponses:


129

Il y en a un dans 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

[Une chose dont il faut se méfier - juste un conseil - est que le paramètre passant est un peu large. En raison de la façon dont le code est configuré, si vous écrivez accidentellement à la scipy.stats.norm(mean=100, std=12)place de scipy.stats.norm(100, 12)ou scipy.stats.norm(loc=100, scale=12), il l'acceptera, mais supprimera silencieusement ces arguments de mot-clé supplémentaires et vous donnera la valeur par défaut (0,1).]


3
Comment obtiendriez-vous les probabilités des plages? Dites de 98 à 102?
Leon

2
@DSM: Dans votre exemple ci-dessus, lorsque vous dites scipy.stats.norm(100, 12).pdf(98), cela signifie-t-il la probabilité d'obtenir 98 dans une distribution avec mean 100 et stddev 12est 0.032?
Srivatsan

14
@ThePredator: non, la probabilité d'obtenir 98 dans une distribution normale avec une moyenne de 100 et stddev 12 est nulle. :-) La densité de probabilité est de 0,032.
DSM

La densité de probabilité dans ce cas signifie la valeur y, étant donné la valeur x 1,42 pour la distribution normale. cdf signifie ce que nous appelons l'aire sous la courbe.
déchiquetage

5
@Leon, c'est rv.cdf(102) - rv.cdf(98)là que rv = scipy.stats.norm(100, 12).
fuglede

46

Scipy.stats est un excellent module. Juste pour proposer une autre approche, vous pouvez la calculer directement en utilisant

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

Cela utilise la formule trouvée ici: http://en.wikipedia.org/wiki/Normal_distribution#Probability_density_function

tester:

>>> normpdf(7,5,5)  
0.07365402806066466
>>> norm(5,5).pdf(7)
0.073654028060664664

Hé, c'est une très bonne réponse. Pourriez-vous fournir une explication étape par étape, peut-être?
Llamageddon

Cette méthode nécessite moins de temps de calcul que scipy
mkm

Mais scipy peut gérer des tableaux de moyennes, stdevs et échantillons: mean = [5, 10, 20] stddev = [20, 30, 40] for x in ([5, 10, 20], [10, 20, 40], [15, 30, 50],): prob = scipy.stats.norm (mean, stddev) .cdf (x) print (f'prob = {prob} ') sorties: prob = [0.5 0.5 0.5] prob = [ 0,59870633 0,63055866 0,69146246] prob = [0,69146246 0,74750746 0,77337265]
John Deighan

16

Voici plus d'informations . Vous avez d'abord affaire à une distribution figée (figée dans ce cas signifie que ses paramètres sont définis sur des valeurs spécifiques). Pour créer une distribution figée:

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

Je ne remercierai jamais assez celui qui a écrit cette réponse. Je cherchais partout pour résoudre ce problème mais je ne pouvais pas le trouver. Et l'ajout des commentaires avec le code m'a vraiment aidé à comprendre ce qui se passe. Merci beaucoup.
bhola prasad le

Je veux juste poser une question, comment calculer ces probabilités lorsque les données ne sont pas normalement distribuées? Que dois-je faire dans ce cas?
bhola prasad le

12

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 densité de probabilité ( pdf- probabilité qu'un échantillon aléatoire X soit proche de la valeur x donnée) pour une moyenne ( mu) et un écart type ( sigma) donnés :

from statistics import NormalDist

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

Notez également que l' NormalDistobjet fournit également la fonction de distribution cumulative ( cdf- probabilité qu'un échantillon aléatoire X soit inférieur ou égal à x):

NormalDist(mu=100, sigma=12).cdf(98)
# 0.43381616738909634

4

Au cas où vous souhaiteriez trouver la zone entre 2 valeurs de x moyenne = 1; écart type = 2; la probabilité de x entre [0,5,2]

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

3

La formule citée de wikipedia mentionnée dans les réponses ne peut pas être utilisée pour calculer les probabilités normales. Vous auriez à écrire une fonction d'approximation d'intégration numérique en utilisant cette formule afin de calculer la probabilité.

Cette formule calcule la valeur de la fonction de densité de probabilité. Puisque la distribution normale est continue, vous devez calculer une intégrale pour obtenir des probabilités. Le site wikipedia mentionne le CDF, qui n'a pas de forme fermée pour la distribution normale.


3
Merci pour votre contribution, même si elle conviendrait mieux comme commentaire à la réponse à laquelle vous faites référence: si je comprends bien, vous ne répondez pas vraiment à la question initiale. De cette façon, tout le monde verra d'un premier coup d'œil de quoi vous parlez.
Pierre Prinetti

1

J'ai écrit ce programme pour faire le calcul pour vous. Entrez simplement dans les statistiques récapitulatives. Pas besoin de fournir un tableau:

Test Z à un échantillon pour une proportion de population:

Pour ce faire pour la moyenne plutôt que pour la proportion, modifiez la formule de z en conséquence

EDIT:
Voici le contenu du lien:

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)

2
Bien que le lien puisse fournir une réponse précieuse, SO demande aux utilisateurs d'afficher leur code ici sur SO Les liens sont utiles comme référence, mais ils ont tendance à se rompre après un certain temps, rendant les solutions inaccessibles aux futurs visiteurs.
M. T

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.