【问题标题】:How to calculate probability in a normal distribution given mean & standard deviation?如何计算给定均值和标准差的正态分布中的概率?
【发布时间】:2012-09-06 22:22:52
【问题描述】:

如何在 Python 中计算给定均值、std 的正态分布概率?我总是可以根据这个问题中的 OP 所做的定义明确地编写我自己的函数:Calculating Probability of a Random Variable in a Distribution in Python

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

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

Perl 中有一个类似的问题:How can I compute the probability at a point given a normal distribution in Perl?。但我在 Python 中没有看到。

Numpy 有一个random.normal 函数,但它就像采样,不是我想要的。

【问题讨论】:

    标签: python statistics scipy probability


    【解决方案1】:

    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)scipy.stats.norm(loc=100, scale=12),那么它会接受它,但会默默地丢弃那些额外的关键字参数并给你默认值 (0,1 ).]

    【讨论】:

    • 如何从范围中获得概率?从 98 到 102 说?
    • @DSM:在你上面的例子中,当你说scipy.stats.norm(100, 12).pdf(98)时,这是否意味着在mean 100 stddev 12的分布中得到98的概率是0.032
    • @ThePredator:不,在平均值为 100 且标准差为 12 的正态分布中得到 98 的概率为零。 :-) 密度的概率是0.032。
    • 这种情况下的概率密度是指 y 值,给定正态分布的 x 值 1.42。 cdf 表示我们所说的曲线下面积。
    • @Leon,那是rv.cdf(102) - rv.cdf(98) rv = scipy.stats.norm(100, 12)
    【解决方案2】:

    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
    

    【讨论】:

    • 嘿,这是一个非常好的答案。或许您介意提供一步一步的解释吗?
    • 这个方法比scipy需要更少的计算时间
    • 但是 scipy 可以处理均值、标准差和样本数组: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}') 输出:prob = [0.5 0.5 0.5]概率=[0.59870633 0.63055866 0.69146246]概率=[0.69146246 0.74750746 0.77337265]
    【解决方案3】:

    您可以只使用数学库中内置的错误函数,如他们的website 所述。

    【讨论】:

    【解决方案4】:

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

    该公式计算概率密度函数的值。由于正态分布是连续的,因此您必须计算积分才能获得概率。*网站提到了 CDF,它没有正态分布的封闭形式。

    【讨论】:

    • 感谢您的贡献,尽管它更适合作为对您所指答案的评论:如果我理解得很好,您并没有真正回答原始问题。这样,每个人都会第一眼看到你在说什么。
    【解决方案5】:

    这里是more info。 首先,您正在处理一个冻结分布(在这种情况下冻结意味着它的参数设置为特定值)。创建冻结分布:

    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
    

    【讨论】:

    • 我非常感谢写这个答案的人。我到处寻找解决这个问题但无法找到它。添加带有代码的 cmets 确实帮助我理解了正在发生的事情。非常感谢。
    • 只想问一个问题,当数据不是正态分布时,这些概率如何计算?在这种情况下我该怎么办?
    【解决方案6】:

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

    One-Sample Z-Test for a Population Proportion:

    要对平均值而不是比例执行此操作,请相应地更改 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)
    

    【讨论】:

    • 虽然该链接可能会提供有价值的答案,但 SO asks users to post their code here on SO 链接可用作参考,但它们往往会在一段时间后断开,从而使未来的访问者无法访问解决方案。
    【解决方案7】:

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

    它可用于获取给定 概率密度函数pdf - 随机样本 X 接近给定值 x 的可能性) em>平均值 (mu) 和标准差 (sigma):

    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
    

    【讨论】:

      【解决方案8】:

      如果您想找到 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)
      

      【讨论】:

        【解决方案9】:

        请注意,probability 不同于 probability density pdf(),之前的一些答案提到了这一点。 概率是变量具有特定值的机会,而概率密度是变量接近特定值的机会,即在一定范围内的概率。因此,要获得概率,您需要计算给定区间内概率密度函数的积分。作为一个近似值,您可以简单地将概率密度乘以您感兴趣的区间,这将为您提供实际概率。

        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
        

        上面的代码将为您提供变量在 -10 到 10 之间的正态分布中具有 21 个数据点的精确值 5 的概率(意味着间隔为 1)。您可以使用固定的间隔值,具体取决于您想要达到的结果。

        【讨论】:

        • 我认为提问者指的是“可能性”而不是真正的“概率”。
        【解决方案10】:

        我想说:提问者在问“如何计算给定数据点在给定均值和标准差的正态分布中的可能性?”而不是“如何在给定均值和标准差的情况下计算正态分布中的概率?”。

        对于“概率”,它必须介于 0 和 1 之间,但对于“可能性”,它必须是非负数(不一定介于 0 和 1 之间)。

        您可以使用scipy.stats.multivariate_normal 中的multivariate_normal.pdf(x, mean= mean_vec, cov=cov_matrix) 来计算它。

        【讨论】:

          最近更新 更多