如何计算累积正态分布?

Posted

技术标签:

【中文标题】如何计算累积正态分布?【英文标题】:How to calculate cumulative normal distribution? 【发布时间】:2010-10-23 00:02:34 【问题描述】:

我正在 Numpy 或 Scipy(或任何严格的 Python 库)中寻找一个函数,该函数将为我提供 Python 中的累积正态分布函数。

【问题讨论】:

【参考方案1】:

这是一个例子:

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

换句话说,大约 95% 的标准正态区间位于两个标准差之内,以标准均值 0 为中心。

如果您需要逆 CDF:

>>> norm.ppf(norm.cdf(1.96))
array(1.9599999999999991)

【讨论】:

另外,您可以指定均值 (loc) 和方差 (scale) 作为参数。例如,d = norm(loc=10.0, scale=2.0); d.cdf(12.0);详情在这里:docs.scipy.org/doc/scipy-0.14.0/reference/generated/… @Irvan,比例参数实际上是标准差,而不是方差。 为什么 scipy 将它们命名为 locscale ?我使用了help(norm.ppf),但是locscale 到底是什么 - 需要帮助...... @javadba - 位置和规模是统计中更通用的术语,用于参数化各种分布。对于正态分布,它们与均值和标准差一致,但对于其他分布则不然。 @MichaelOhlrogge 。谢谢!这是 NIST 的一个页面,进一步解释 itl.nist.gov/div898/handbook/eda/section3/eda364.htm【参考方案2】:

现在回答这个问题可能为时已晚,但由于谷歌仍然在此引导人们,我决定在这里写下我的解决方案。

即从Python 2.7开始,math库已经集成了错误函数math.erf(x)

erf() 函数可用于计算累积标准正态分布等传统统计函数:

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

参考:

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

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

How are the Error Function and Standard Normal distribution function related?

【讨论】:

这正是我想要的。如果我以外的其他人想知道如何使用它来计算“位于标准分布内的数据百分比”,那么:1 - (1 - phi(1)) * 2 = 0.6827 (“68% 的数据在 1 个标准内偏差") 对于一般的正态分布,应该是def phi(x, mu, sigma): return (1 + erf((x - mu) / sigma / sqrt(2))) / 2【参考方案3】:

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

它可用于获取给定的累积分布函数cdf - 随机样本 X 小于或等于 x 的概率) 平均值 (mu) 和标准差 (sigma):

from statistics import NormalDist

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

这可以简化为标准正态分布mu = 0sigma = 1):

NormalDist().cdf(1.96)
# 0.9750021048517796

NormalDist().cdf(-1.96)
# 0.024997895148220428

【讨论】:

基于一些快速检查,这比 scipy.stats 中的 norm.cdf 快得多,并且比 erf 的 scipy 和数学实现快一点。 这是否矢量化?或者如果他们需要计算在数组中所有点评估的 CDF,是否应该使用 scipy 实现?【参考方案4】:

改编自这里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))

【讨论】:

由于std lib实现了math.erf(),所以不需要sep实现。 我找不到答案,这些数字是从哪里来的? @TmSmth 如果我不得不猜测这看起来像是指数内部的某种近似值,所以你可能可以在稍微摆弄你的函数后用某种泰勒展开来计算它们(改变vars,然后说 r = t * exp( - z**2 -f(t)) 并对 f 进行泰勒展开(可以用数字找到【参考方案5】:

以 Unknown 的示例为基础,在许多库中实现的函数 normdist() 的 Python 等效项是:

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

【讨论】:

【参考方案6】:

Alex 的回答向您展示了标准正态分布的解决方案(均值 = 0,标准差 = 1)。如果您有meanstd(即sqr(var))的正态分布并且您想计算:

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)

阅读更多关于cdf here 和正态分布的scipy 实现与许多公式here。

【讨论】:

【参考方案7】:

从上面拍摄:

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

对于双尾测试:

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

【讨论】:

【参考方案8】:

像这样简单:

import math
def my_cdf(x):
    return 0.5*(1+math.erf(x/math.sqrt(2)))

我在这个页面找到了公式https://www.danielsoper.com/statcalc/formulas.aspx?id=55

【讨论】:

以上是关于如何计算累积正态分布?的主要内容,如果未能解决你的问题,请参考以下文章

如何在python中计算正态累积分布函数的倒数?

在 Python 中计算累积分布函数 (CDF)

R语言经验累积分布函数计算和绘制实战

标准正态分布的累积密度函数

gini基尼系数,累积准确度分布,AUC(风控模型核心指标)

JavaScript中的分位数/百分点/百分位数/逆累积分布函数