Como calcular a probabilidade em uma distribuição normal dada média e desvio padrão?

94

Como calcular a probabilidade na distribuição normal dada a média, std em Python? Sempre posso codificar explicitamente minha própria função de acordo com a definição, como fez o OP nesta questão: Calculando a probabilidade de uma variável aleatória em uma distribuição em Python

Apenas saber se há uma chamada de função de biblioteca permitirá que você faça isso. Na minha imaginação seria assim:

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

Há uma questão semelhante em Perl: como posso calcular a probabilidade em um ponto dada uma distribuição normal em Perl? . Mas eu não vi um em Python.

Numpytem uma random.normalfunção, mas é como amostrar, não exatamente o que eu quero.

Clwen
fonte

Respostas:

130

Existe um em 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

[Uma coisa a ter em conta - apenas uma dica - é que a passagem de parâmetros é um pouco ampla. Devido à forma como o código está configurado, se você acidentalmente escrever em scipy.stats.norm(mean=100, std=12)vez de scipy.stats.norm(100, 12)ou scipy.stats.norm(loc=100, scale=12), ele o aceitará, mas descartará silenciosamente esses argumentos de palavra-chave extras e fornecerá o padrão (0,1).]

DSM
fonte
3
Como você obteria probabilidades de intervalos? Diga de 98 a 102?
Leon
2
@DSM: Em seu exemplo acima, quando você diz scipy.stats.norm(100, 12).pdf(98), isso significa a probabilidade de obter 98 em uma distribuição com mean 100 e stddev 12é 0.032?
Srivatsan
14
@ThePredator: não, a probabilidade de obter 98 em uma distribuição normal com média 100 e stddev 12 é zero. :-) A densidade de probabilidade é 0,032.
DSM
A densidade de probabilidade, nesse caso, significa o valor y, dado o valor x 1,42 para a distribuição normal. cdf significa o que chamamos de área sob a curva.
destruição
5
@Leon, é rv.cdf(102) - rv.cdf(98)onde rv = scipy.stats.norm(100, 12).
fuglede
47

Scipy.stats é um ótimo módulo. Apenas para oferecer outra abordagem, você pode calculá-lo diretamente 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

Ele usa a fórmula encontrada aqui: http://en.wikipedia.org/wiki/Normal_distribution#Probability_density_function

testar:

>>> normpdf(7,5,5)  
0.07365402806066466
>>> norm(5,5).pdf(7)
0.073654028060664664
jiminy_crist
fonte
Ei, esta é uma resposta muito boa. Você se importaria de fornecer uma explicação passo a passo, talvez?
Llamageddon
Este método precisa de menos tempo de computação do que scipy
mkm
Mas o scipy pode lidar com matrizes de meios, desvios padrão e amostras: média = [5, 10, 20] desvios padrão = [20, 30, 40] para x em ([5, 10, 20], [10, 20, 40], [15, 30, 50],): prob = scipy.stats.norm (média, stddev) .cdf (x) print (f'prob = {prob} ') saídas: prob = [0,5 0,5 0,5] prob = [ 0,59870633 0,63055866 0,69146246] prob = [0,69146246 0,74750746 0,77337265]
John Deighan
17

Aqui estão mais informações . Primeiro, você está lidando com uma distribuição congelada (congelada, neste caso, significa que seus parâmetros são definidos com valores específicos). Para criar uma distribuição 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
fonte
Não posso agradecer o suficiente a quem escreveu esta resposta. Eu estava procurando em todos os lugares para resolver isso, mas não consegui encontrar. E adicionar os comentários com o código realmente me ajudou a entender o que está acontecendo. Muito obrigado.
bhola prasad
Só quero fazer uma pergunta, como calcular essas probabilidades quando os dados não são normalmente distribuídos? O que devo fazer neste caso?
bhola prasad
13

Inicialmente Python 3.8, a biblioteca padrão fornece o NormalDistobjeto como parte do statisticsmódulo.

Ele pode ser usado para obter a função de densidade de probabilidade ( pdf- probabilidade de que uma amostra aleatória X estará perto de um determinado valor x) para uma determinada média ( mu) e desvio padrão ( sigma):

from statistics import NormalDist

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

Observe também que o NormalDistobjeto também fornece a função de distribuição cumulativa ( cdf- probabilidade de que uma amostra aleatória X seja menor ou igual a x):

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

Caso você queira encontrar a área entre 2 valores de x média = 1; desvio padrão = 2; a probabilidade de x entre [0,5,2]

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

A fórmula citada da wikipedia mencionada nas respostas não pode ser usada para calcular probabilites normais. Você teria que escrever uma função de aproximação de integração numérica usando essa fórmula para calcular a probabilidade.

Essa fórmula calcula o valor da função de densidade de probabilidade. Como a distribuição normal é contínua, você deve calcular uma integral para obter probabilidades. O site wikipedia cita o CDF, que não possui um formulário fechado para a distribuição normal.

user2724943
fonte
3
Obrigado pela sua contribuição, embora caberia melhor como um comentário à resposta a que se refere: se bem entendi, você não está realmente respondendo à pergunta original. Dessa forma, todos verão à primeira vista do que você está falando.
Pierre Prinetti
1

Escrevi este programa para fazer as contas para você. Basta entrar nas estatísticas de resumo. Não há necessidade de fornecer uma matriz:

Teste Z de uma amostra para uma proporção da população:

Para fazer isso para a média em vez da proporção, altere a fórmula para z de acordo

EDITAR:
Aqui está o conteúdo do link:

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
fonte
2
Embora o link possa fornecer uma resposta valiosa, o SO pede aos usuários que postem seu código aqui no SO. Os links são úteis como referência, mas tendem a quebrar depois de um tempo, tornando as soluções inacessíveis para futuros visitantes.
Sr. T
0

Você pode simplesmente usar a função de erro que está embutida na biblioteca matemática, conforme declarado em seu site .

user2340146
fonte
Não, @ user2340146, também em Python 2: docs.python.org/2/library/math.html#math.erf
BoltzmannBrain
0

Observe que a probabilidade é diferente da densidade de probabilidade pdf() , à qual algumas das respostas anteriores se referem. Probabilidade é a chance de que a variável tenha um valor específico, enquanto a densidade de probabilidade é a chance de que a variável esteja perto de um valor específico, significando probabilidade ao longo de um intervalo. Portanto, para obter a probabilidade, você precisa calcular a integral da função de densidade de probabilidade em um determinado intervalo. Como uma aproximação, você pode simplesmente multiplicar a densidade de probabilidade pelo intervalo de seu interesse e isso lhe dará a probabilidade real.

import numpy as np
from scipy.stats import norm

data_start = -10
data_end = 10
data_points = 21
data = np.linspace(data_start, data_end, data_points)

point_of_interest = 5
mu = np.mean(data)
sigma = np.std(data)                                   
interval = (data_end - data_start) / (data_points - 1)
probability = norm.pdf(point_of_interest, loc=mu, scale=sigma) * interval

O código acima lhe dará a probabilidade de que a variável terá um valor exato de 5 em uma distribuição normal entre -10 e 10 com 21 pontos de dados (o que significa que o intervalo é 1). Você pode brincar com um valor de intervalo fixo, dependendo dos resultados que deseja alcançar.

tsveti_iko
fonte