Como calcular a distribuição normal cumulativa?

99

Estou procurando uma função em Numpy ou Scipy (ou qualquer biblioteca Python rigorosa) que me dará a função de distribuição normal cumulativa em Python.

martineau
fonte

Respostas:

125

Aqui está um exemplo:

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

Em outras palavras, aproximadamente 95% do intervalo normal padrão encontra-se dentro de dois desvios padrão, centrados em uma média padrão de zero.

Se você precisa do CDF inverso:

>>> norm.ppf(norm.cdf(1.96))
array(1.9599999999999991)
Alex Reynolds
fonte
9
Além disso, você pode especificar a média (loc) e a variância (escala) como parâmetros. por exemplo, d = norma (loc = 10,0, escala = 2,0); d.cdf (12,0); Detalhes aqui: docs.scipy.org/doc/scipy-0.14.0/reference/generated/...
Irvan
6
@Irvan, o parâmetro de escala é na verdade o desvio padrão, NÃO a variância.
qkhhly
2
Por que scipy os nomeia como loce scale? Eu usei o help(norm.ppf)mas então o que diabos são loce scale- preciso de uma ajuda para a ajuda ..
javadba
2
@javadba - localização e escala são termos mais gerais em estatísticas que são usados ​​para parametrizar uma ampla gama de distribuições. Para a distribuição normal, eles se alinham com média e sd, mas não para outras distribuições.
Michael Ohlrogge
1
@MichaelOhlrogge. THX! Aqui está uma página do NIST explicando melhor itl.nist.gov/div898/handbook/eda/section3/eda364.htm
javadba
40

Pode ser tarde demais para responder à pergunta, mas como o Google ainda conduz pessoas aqui, decido escrever minha solução aqui.

Ou seja, desde o Python 2.7, a mathbiblioteca integrou a função de erromath.erf(x)

A erf()função pode ser usada para calcular funções estatísticas tradicionais, como a distribuição normal padrão cumulativa:

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

Ref:

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

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

Como a função de erro e a função de distribuição normal padrão estão relacionadas?

WTIFS
fonte
3
Isso era exatamente o que eu estava procurando. Se alguém além de mim se perguntar como isso pode ser usado para calcular a "porcentagem de dados dentro da distribuição padrão", bem: 1 - (1 - phi (1)) * 2 = 0,6827 ("68% dos dados dentro de 1 padrão desvio ")
Hannes Landeholm
1
Para uma distribuição normal geral, seria def phi(x, mu, sigma): return (1 + erf((x - mu) / sigma / sqrt(2))) / 2.
Bernhard Barker
19

Adaptado daqui 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))
Desconhecido
fonte
3
Visto que a lib std implementa math.erf (), não há necessidade de uma implementação em sep.
Marc
Não consegui encontrar uma resposta, de onde vêm esses números?
TmSmth de
15

Para desenvolver o exemplo de Unknown, o equivalente em Python da função normdist () implementada em muitas bibliotecas seria:

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

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

Pode ser usado para obter a função de distribuição cumulativa ( cdf- probabilidade de que uma amostra aleatória X seja menor ou igual a x) para uma determinada média ( mu) e desvio padrão ( sigma):

from statistics import NormalDist

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

Que pode ser simplificado para a distribuição normal padrão ( mu = 0e sigma = 1):

NormalDist().cdf(1.96)
# 0.9750021048517796

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

A resposta de Alex mostra uma solução para a distribuição normal padrão (média = 0, desvio padrão = 1). Se você tem distribuição normal com meane std(que é sqr(var)) e deseja 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)

Leia mais sobre o cdf aqui e a implementação do scipy da distribuição normal com muitas fórmulas aqui .

Salvador Dalí
fonte
2

Tirado de cima:

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

Para um teste bicaudal:

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

Como o Google dá essa resposta para a pesquisa netlogo pdf , aqui está a versão netlogo do código python acima

    ;; Função de densidade cumulativa de distribuição normal
    para relatar normcdf [x mu sigma]
        deixe tx - mu
        deixe y 0.5 * erfcc [- t / (sigma * sqrt 2.0)]
        if (y> 1.0) [set y 1.0]
        relatório y
    fim

    ;; Função de densidade de probabilidade de distribuição normal
    para relatar normpdf [x mu sigma]
        deixe u = (x - mu) / abs sigma
        deixe y = 1 / (sqrt [2 * pi] * abs sigma) * exp (- u * u / 2,0)
        relatório y
    fim

    ;; Função de erro complementar
    relatar erfcc [x]
        deixe z abs x
        deixe t 1,0 / (1,0 + 0,5 * z)
        deixe 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) [relatório r] [relatório 2.0 - r]
    fim

platípódio
fonte
6
A questão é sobre Python, não NetLogo. Esta resposta não deveria estar aqui. E, por favor, não edite a pergunta para mudar seu significado.
intervalo de
Estou ciente de que esta não é a forma preferida, mas acho que é mais útil dessa forma, já que as pessoas são direcionadas para esta página pelo google (atualmente ...)
platipodium 18/10/12