我必须计算三重求和(嵌套二项式CDF),公式如下:x1c 0d1x
它是一个二项式求和,首先从k = 0到C,然后m = 0到k,f = 0到C-k,这里s是一个函数,它的输入在0和1之间,输出在(0,1)之间。
我需要帮助找到一个有效的方法来在python中执行此操作。现在我使用的是三重循环,它工作得很好,但对于大型C来说效率不高。我目前使用的三重循环如下:
这里的s基本上是线性的,但它可以采取任何需要的形状。r也取0.1
import numpy as np
from math import comb
def s(d):
return d * (0.99 - 0.01) + 0.01
S = 0
C = 100
for k in range(C):
for m in range(k):
for f in range(C-k):
S += comb(C, k) * (((0.1)**(k))*((0.9)**(C-k))) * comb(k, m) * comb(C-k, f) * (2**(-C)) * s((f+m)/C)
字符串
有没有更有效的方法可以使用?
Edit:s只是一个以下形式的函数,它接受0到1之间的输入,并根据其形状给出0.01到0.99之间的输出。在示例代码中,它是线性的,但它可以是指数的或其他的。
Edit 2:函数's'不能从第一个求和中出来,在我提供的公式中,它可能是由于打字错误。它现在是固定的沿着随着输入chrslg的建议。
2条答案
按热度按时间tp5buhyn1#
所以
s
只是一个仿射函数。这允许一些优化从
字符串
请注意,此代码中有一个错误:数学符号中的Σ使用包含的边界(在这种公式中,通常有
from 0 to n included
,这意味着n+1次迭代。因为当你抽屉里有n只袜子,然后随机取一个数字,你可以取0只袜子,1只袜子,2只袜子,…最多n只袜子,包括:D)。代码应该是
型
我们可以从循环中得到所有不依赖于循环索引的内容,正如我在注解中提到的
型
在这里,我只是模仿数学方程而不是代码。有些操作已经被这样分解了。
当然,我不能像这样直接删除内部循环,因为现在你已经用不独立于
f
的s((m+f)/C)
替换了s(m/C)
。但由于
s
是仿射的,我们可以很容易地将其替换为型
一个常数项,一个与f成比例的项
由于Σcomb(n,k)是2,Σk.comb(n,k)是n×2 ¹,我们可以用
型
所以这是一个循环!现在我们有2个循环,而不是3个。但还没结束!
合并
Sf=
和Sm +=
行型
请注意,在这里,我们乘以
comb(k,m)
是由常数项组成的(0.01*2**(-k)
或0.98/C*(C-k)*2**(-k-1)
是常数项,就m
而言),并且与m
项成比例。因此,使用相同的Σcomb(n,k) = 2ᵏ
和Σk.comb(n,k) = k.2ᵏ⁻¹
公式,我们可以再次重写型
第二圈开始了!只剩一个了。还没结束!
可以简化为
型
甚至
型
所以Sm=0.5明显
型
但是
Σ comb(n,k) aᵏbⁿ⁻ᵏ
是(a+b)的众所周知的发展。因此,0.5×(r +(1-r))= 0.5×1 = 0.5因此,您的代码的最终简化(对不起,不能做得比这更好!)
型
你可以很容易地检查,一旦边界问题得到纠正,你的代码也返回0.5,不管参数(C和r)是多少。
一些 numpy 把戏
由于这应该是一个numpy问题,而不是一个数学简化问题,下面是如何使用numpy加速这种计算。
假设您正在尝试计算内部循环
型
(the更有趣的一个。因为这个我想知道
s
,特别是如果它是向量化的。我最初的计划是给予我现在给出的答案,如果s
是可向量的,也就是说s
是否可以同时使用标量和数组作为参数。但是我不得不改变我的计划,当我看到s
甚至是仿射,这是更好的。但是,好吧,让我们假设s
更复杂,例如包含sin
,log
,甚至只是一些高阶多项式,这些多项式使我的形式计算变得不可能)如果,我们可以使用向量化函数(同样,如果被要求,可以在整个数组上工作的函数),一次计算一个
C-k+1
值的向量,那么我们可以跳过for
循环,并使用numpy的sum
方法求和。它在现实中仍然是一个for
循环。但是一个隐藏的,更重要的是,发生在numpy优化的C代码中的一个,在我们的慢python节点中。我们可以从
f
的值向量开始f=np.arange(C-k+1.0)
。请注意1.0
,lazy方式来确保它是浮动的好消息是你的
s
(可能还有你能想到的所有s
,甚至是我提到的sin
,log
或更高次多项式)都是矢量化的。因此,我们可以很容易地计算出s((f+m)/C)
的向量。简单地说,就是这样做:如果f
是向量,那么(f+m)/C
也是,因为s
是向量化的。所以,最难的部分是梳子部分。
有了numpy,你可以用
cumprod
来完成型
现在我们有一个向量
comb(f,C-k)
和一个向量s((f+m)/C)
。要得到所有项的向量,我们只需要将两者相乘型
请注意,如果您愿意使用scipy,它甚至更简单,因为scipy包含一个向量化的
comb
函数型
这一次,我没有数学技巧。我没有简化任何东西。这只是编码技巧,使循环消失。它仍然存在(scipy的
comb
,numpy的+
,-
,*
和.sum()
)。现在甚至有5个(非嵌套的,比纯Python循环快5倍多)jfgube3f2#
你可以每
k
只计算一次comb(C, k) * (((0.1)**(k))*((0.9)**(C-k)))
,comb(k, m)
只计算一次m
,如下所示:字符串