python求标准正态分布,python对数正态分布函数
标准正态分布的分布函数 (x) (x)可以说是统计计算中非常重要的一个函数,在基本正态分布的地方都会或多或少用到。在一些具体问题中,我们需要多次计算这个函数的值。比如我经常需要计算正态分布和另一个随机变量之和的分布。这时候就需要用数值积分了,被积函数包含 (x) (x)。如果z?N(0,1),X?f(x)Z?N(0,1),X?F(x),ff是XX的密度函数,那么Z XZ X的分布函数为
P(Z Xt)= ?(t?x)f(x)dxP(Z Xt)=?(t?x)f(x)dx
我们知道, (x) (x)没有简单的显式表达式,需要通过一定的数值方法来计算。在大多数科学计算软件中,计算的准确性永远是第一位的,所以它的算法一般比较复杂。当这个函数需要计算上千次时,速度可能会成为瓶颈。
当然,有问题就会有对策。一种常见的做法是稍微放弃一些精度,以换取更简单的计算。在大多数实际应用中,合理的误差,如10?710?一般7个就够了。本文将介绍两个简单的方法,都比R中的pnorm()快,误差控制在10?710?7的水平。
第一种方法来自经典参考书《abramowitz and stegun:数学函数手册》。
公式26.2.17。基本思想是把 (x) (x)表示成正态密度函数?(x)?(x)和一个有理函数的乘积。这种方法可以保证误差小于7.510?87.510?8.C实现可以在这里找到。(代码中的常数与书中略有不同,因为代码是为误差函数erf(x)erf(x)编写的,它与 (x) (x)有一些常数不同)
我们来对比一下这个方法和R中pnorm()的速度,验证一下它的准确性。
库(Rcpp)source CPP( test _ as 26217 . CPP )x=seq(-6,6,by=1e-6) system.time(y
可以看出,AS 26.2.17的速度是pnorm()的三倍左右,误差在预定范围内,对计算效率是一个很大的提升。
那么有可能更快吗?答案是肯定的,而且这个方法你其实已经用过很多次了。什么,你不相信我?看看下图,你就明白了。
没错,这个更快的方法其实就是两个字:查表。它的基本思想是,我们预先计算一系列函数值(xi, (xi)) (xi, (xi)),然后当我们需要计算某一点x0x0时,我们会找到最近的两个点xkxk和xk 1xk 1,然后通过线性插值得到 (x0) (x0)的近似值:
(x0)x0?xkxk 1?xk(Xi 1)xk 1?x0xk 1?xk(Xi)(x0)x0?xkxk 1?xk(Xi 1)xk 1?x0xk 1?xk(Xi)
什么?觉得这个方法太简单了?别着急,这里面还是有很多知识的。我们之前说过,我们需要确保这个方法的误差不超过?=10?7?=10?7,所以要合理选择预计算点。由于(?x)=1?(x)(?x)=1? (x),我们暂时只需要考虑xx为正的情况。如果xi=ih,i=0,1,…,Nxi=ih,i=0,1,…,N,那么函数ff线性插值的误差不会超过(来源)
e(x)18fh2E(x)18fH2
其中f f "是函数的二阶导数的最大绝对值。对于正态分布函数,等于?(1)0.242?(1)0.242。所以设E(x)=10?7E(x)=10?7,我们可以解出h0.001818h0.001818。最后,只要xN5.199xN5.199,即N2860N2860,且xxNxxN的所有值都等于1,就能保证 (x) (x)在整个实数域内的近似误差小于10?710?7。
我把这个简单方法的实现放在了Github上,源程序和测试代码也可以在文末找到。它是这样表现的:
库(Rcpp)source CPP( test _ fastncdf . CPP )x=seq(-6,6,by=1e-6) system.time(fasty
与之前的结果相比,速度相当于pnorm()的15倍!
我们似乎总是认为,随着计算机和统计软件的普及,一些传统的做法会逐渐被淘汰。比如现在,除了考试,我们可能大部分时间都在用软件,而不是正常的概率表。从教学和实际应用的角度来看,这种做法是应该推广的,但并不妨碍我们从一些“旧知识”中吸取营养。关于这种笨拙的做法有很多故事,比如这个广为流传的故事。在计算资源匮乏的时代,科学家们想出了各种别出心裁的办法来解决他们遇到的各种问题。现在的电脑性能远不能和当年相比,但是很多前辈的智慧依然穿越时间帮助我们到现在。不得不说,这也是一种缘分。
出发地:统计之都
来源:链接:本文采用“CC BY-SA 4.0 CN”协议转载学习交流,内容版权归原作者所有。如涉及作品、版权等问题,请联系“我们”处理。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。