在给定均值和标准差的情况下,如何计算正态分布中的概率?


91

如何在Python中给定平均值std的正态分布中计算概率?我总是可以像这个问题中的OP一样根据定义明确地编写自己的函数:计算Python分布中随机变量的概率

只是想知道是否有一个库函数调用将允许您执行此操作。在我的想象中,它将是这样的:

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

Perl中有一个类似的问题:如何在给定的Perl正态分布下计算点的概率?。但是我没有在Python中看到它。

Numpy有一个random.normal功能,但这就像采样,不完全是我想要的。

Answers:


129

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

[要提防的一件事-只是一个提示-参数传递有点宽泛。由于代码的设置方式,如果您不小心编写了scipy.stats.norm(mean=100, std=12)代替scipy.stats.norm(100, 12)or的代码scipy.stats.norm(loc=100, scale=12),则它将接受它,但会静默丢弃那些多余的关键字参数,并为您提供默认值(0,1)。]


3
您如何从范围中获得概率?说98-102?
莱昂

2
@DSM:在上面的示例中,当您说时scipy.stats.norm(100, 12).pdf(98),这是否意味着使用mean 100 stddev 12是的分布获得98的概率0.032
Srivatsan

14
@ThePredator:不,以均值为100且stddev 12为正态分布的98的概率为零。:-)概率密度为0.032。
DSM 2015年

在这种情况下,概率密度表示y值,给定正态分布的x值为1.42。cdf表示我们称为曲线下的面积。
粉碎

5
@Leon,rv.cdf(102) - rv.cdf(98)在那里rv = scipy.stats.norm(100, 12)
fuglede

46

Scipy.stats是一个很棒的模块。只是提供另一种方法,您可以直接使用

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

这使用此处找到的公式:http : //en.wikipedia.org/wiki/Normal_distribution#Probability_density_function

去测试:

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

嘿,这是一个非常好的答案。您介意提供逐步说明吗?
Llamageddon '16

这种方法需要较少的计算时间比SciPy的
MKM

但是scipy可以处理均值,stdev和样本的数组:x in([[5,10,20],[10,20,40]中的均值= [5,10,20] stddev = [20,30,40], [15,30,50],):概率= scipy.stats.norm(平均值,标准差).cdf(x)打印(f'概率= {概率}')输出:概率= [0.5 0.5 0.5]概率= [ 0.59870633 0.63055866 0.69146246]概率= [0.69146246 0.74750746 0.77337265]
John Deighan

16

这是更多信息。首先,您要处理冻结分发(在这种情况下,冻结意味着将其参数设置为特定值)。要创建冻结分发:

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

无论谁写了这个答案,我都感激不尽。我到处都在寻找解决方案,但找不到。在代码中添加注释确实帮助我了解发生了什么。非常感谢。
bhola prasad

只想问一个问题,当数据不是正态分布时如何计算这些概率?在这种情况下我该怎么办?
bhola prasad

11

从开始Python 3.8,标准库将NormalDist对象作为statistics模块的一部分提供。

对于给定的均值()和标准差(),可以使用它来获取概率密度函数pdf-随机样本X接近给定值x的可能性):musigma

from statistics import NormalDist

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

还要注意,该NormalDist对象还提供了累积分布函数cdf-随机样本X小于或等于x的概率):

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

4

如果您想在x mean = 1的2个值之间找到一个区域;标准偏差= 2; x在[0.5,2]之间的概率

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

2

答案中提到的Wikipedia引用的公式不能用于计算正常概率。您必须使用该公式编写一个数值积分近似函数,以计算概率。

该公式计算概率密度函数的值。由于正态分布是连续的,因此您必须计算积分才能获得概率。维基百科站点提到CDF,对于正常分布,CDF没有封闭形式。


3
感谢您的贡献,尽管它更适合作为您所引用答案的注释:如果我理解得很好,您实际上并没有在回答原始问题。这样,每个人都会乍一看您在说什么。
Pierre Prinetti

1

我写了这个程序来为你做数学。只需输入摘要统计信息即可。无需提供数组:

总体比例的一样本Z检验:

要针对平均值而不是比例进行此操作,请相应地更改z的公式

编辑:
这是链接的内容:

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
尽管该链接可能提供了一个有价值的答案,但SO要求用户在此处将其代码发布在SO上,这些链接可作为参考,但有时它们会中断,从而使将来的访问者无法访问解决方案。
T先生

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.