好的,您似乎对几件事感到很困惑。让我们从头开始:您提到了一个“多维函数”,但接下来继续讨论通常的单变量高斯曲线。这不是一个多维函数:当你对它进行积分时,你只积分了一个变量 (x)。区分很重要,因为有一个称为“多元高斯分布”的怪物,它是一个真正的多维函数,如果集成,则需要对两个或多个变量进行积分(它使用我之前提到的昂贵的蒙特卡洛技术)。但是您似乎只是在谈论常规的单变量高斯,它更容易使用,集成等等。
单变量高斯分布有两个参数,sigma
和mu
, 是我们将表示的单个变量的函数x
。您似乎还携带了一个标准化参数n
(这在几个应用程序中很有用)。归一化参数通常不包含在计算中,因为您可以在最后将它们重新添加(请记住,积分是线性运算符:)int(n*f(x), x) = n*int(f(x), x)
。但如果您愿意,我们可以随身携带;我喜欢正态分布的符号是
N(x | mu, sigma, n) := (n/(sigma*sqrt(2*pi))) * exp((-(x-mu)^2)/(2*sigma^2))
x
(读作“给定sigma
,mu
和的正态分布n
由...给出”)到目前为止,一切都很好;这与您拥有的功能相匹配。请注意,这里唯一真正的变量是x
:其他三个参数对于任何特定的高斯都是固定的。
现在来看一个数学事实:可以证明,所有高斯曲线都具有相同的形状,它们只是稍微移动了一点。所以我们可以使用N(x|0,1,1)
称为“标准正态分布”的 ,并将我们的结果转换回一般的高斯曲线。所以如果你有 的积分N(x|0,1,1)
,你可以简单地计算任何高斯的积分。这个积分出现得如此频繁,以至于它有一个特殊的名字:误差函数 erf
。由于一些旧约定,它不完全是 erf
; 还有一些加法和乘法因素也被随身携带。
如果Phi(z) = integral(N(x|0,1,1), -inf, z)
;也就是说,Phi(z)
是从负无穷到 的标准正态分布的积分z
,那么根据误差函数的定义,它是真的
Phi(z) = 0.5 + 0.5 * erf(z / sqrt(2))
.
同样,如果Phi(z | mu, sigma, n) = integral( N(x|sigma, mu, n), -inf, z)
; 也就是说,是给定参数,和从负无穷大到Phi(z | mu, sigma, n)
的正态分布的积分,那么根据误差函数的定义,它是真的mu
sigma
n
z
Phi(z | mu, sigma, n) = (n/2) * (1 + erf((x - mu) / (sigma * sqrt(2))))
.
如果您想了解更多细节或证明这一事实,请查看有关普通 CDF 的 Wikipedia 文章。
好的,这应该是足够的背景解释。回到你的(编辑的)帖子。您说“ scipy.special 中的 erf(z) 将要求我准确定义 t 最初是什么”。我不知道你的意思是什么;(时间?)在哪里t
进入这个?希望上面的解释稍微揭开了误差函数的神秘面纱,现在更清楚为什么误差函数是适合这项工作的函数。
你的 Python 代码没问题,但我更喜欢闭包而不是 lambda:
def make_gauss(N, sigma, mu):
k = N / (sigma * math.sqrt(2*math.pi))
s = -1.0 / (2 * sigma * sigma)
def f(x):
return k * math.exp(s * (x - mu)*(x - mu))
return f
使用闭包可以预先计算常量k
和s
,因此每次调用返回的函数时需要做的工作更少(如果您正在集成它,这可能很重要,这意味着它将被多次调用)。另外,我避免使用任何求幂运算符**
,这比仅仅写出平方要慢,并将除法提升到内部循环之外并用乘法替换它。我没有看过它们在 Python 中的实现,但是从我上次使用原始 x87 程序集调整内部循环以获得纯速度,我似乎记得加、减或乘法每个大约需要 4 个 CPU 周期,除以大约36,约 200 的幂。那是几年前的事了,所以对这些数字持保留态度;尽管如此,它还是说明了它们的相对复杂性。同样,计算exp(x)
蛮力方法是一个非常糟糕的主意。在编写一个好的实现时,您可以采取一些技巧exp(x)
,使其比一般a**b
风格的幂运算更快、更准确。
我从未使用过常量 pi 和 e 的 numpy 版本;我一直坚持使用普通的旧数学模块版本。我不知道为什么你可能更喜欢任何一个。
我不确定你quad()
打电话的目的是什么。quad(gen_gauss, -inf, inf, (10,2,0))
应该将重新归一化的高斯从负无穷积分到正无穷大,并且应该总是吐出 10(你的归一化因子),因为高斯在实线上积分为 1。任何远离 10 的答案(我不希望正好是10 quad()
,因为毕竟只是一个近似值)意味着某处搞砸了……很难说在不知道实际返回值和可能的内部工作原理的情况下搞砸了什么quad()
。
希望这已经揭开了一些混乱的面纱,并解释了为什么错误函数是您问题的正确答案,以及如果您好奇的话如何自己做这一切。如果我的任何解释不清楚,我建议先快速浏览一下维基百科;如果您仍有疑问,请随时提问。