gpt4 book ai didi

python - `scipy.misc.comb` 比临时二项式计算快吗?

转载 作者:IT老高 更新时间:2023-10-28 22:01:16 25 4
gpt4 key购买 nike

现在是否可以确定 scipy.misc.comb 确实比 ad-hoc 实现更快?

根据旧答案,Statistics: combinations in Python , 这个自制函数在计算组合时比 scipy.misc.combnCr:

def choose(n, k):
"""
A fast way to calculate binomial coefficients by Andrew Dalke (contrib).
"""
if 0 <= k <= n:
ntok = 1
ktok = 1
for t in xrange(1, min(k, n - k) + 1):
ntok *= n
ktok *= t
n -= 1
return ntok // ktok
else:
return 0

但是在我自己的机器上运行了一些测试之后,情况似乎不是这样,使用这个脚本:

from scipy.misc import comb
import random, time

def choose(n, k):
"""
A fast way to calculate binomial coefficients by Andrew Dalke (contrib).
"""
if 0 <= k <= n:
ntok = 1
ktok = 1
for t in xrange(1, min(k, n - k) + 1):
ntok *= n
ktok *= t
n -= 1
return ntok // ktok
else:
return 0

def timing(f):
def wrap(*args):
time1 = time.time()
ret = f(*args)
time2 = time.time()
print '%s function took %0.3f ms' % (f.__name__, (time2-time1)*1000.0)
return ret
return wrap

@timing
def test_func(combination_func, nk):
for n,k in nk:
combination_func(n, k)

nk = []
for _ in range(1000):
n = int(random.random() * 10000)
k = random.randint(0,n)
nk.append((n,k))

test_func(comb, nk)
test_func(choose, nk)

我得到以下输出:

$ python test.py
/usr/lib/python2.7/dist-packages/scipy/misc/common.py:295: RuntimeWarning: overflow encountered in exp
vals = exp(lgam(N+1) - lgam(N-k+1) - lgam(k+1))
999
test_func function took 32.869 ms
999
test_func function took 1859.125 ms

$ python test.py
/usr/lib/python2.7/dist-packages/scipy/misc/common.py:295: RuntimeWarning: overflow encountered in exp
vals = exp(lgam(N+1) - lgam(N-k+1) - lgam(k+1))
999
test_func function took 32.265 ms
999
test_func function took 1878.550 ms

时间分析测试是否表明新的 scipy.misc.comb 比 ad-hoc choose() 函数更快?我的测试脚本是否有任何错误导致计时不准确?

为什么现在 scipy.misc.comb 更快了?是因为一些 cython/c 包装技巧?


已编辑

@WarrenWeckesser 评论后:

在使用 scipy.misc.comb() 时使用默认的浮点近似,计算会因浮点溢出而中断。

(参见 http://docs.scipy.org/doc/scipy-0.16.0/reference/generated/scipy.misc.comb.html 获取文档)

当使用 exact=True 进行测试时,使用以下函数使用长整数而不是 float 进行计算,计算 1000 个组合时会慢很多:

@timing
def test_func(combination_func, nk):
for i, (n,k) in enumerate(nk):
combination_func(n, k, exact=True)

[出]:

$ python test.py
test_func function took 3312.211 ms
test_func function took 1764.523 ms

$ python test.py
test_func function took 3320.198 ms
test_func function took 1782.280 ms

最佳答案

引用scipy.misc.comb的源码,结果的更新例程为:

    val = 1
for j in xrange(min(k, N-k)):
val = (val*(N-j))//(j+1)
return val

而您建议的更新程序是:

    ntok = 1
ktok = 1
for t in xrange(1, min(k, n - k) + 1):
ntok *= n
ktok *= t
n -= 1
return ntok // ktok

我对 SciPy 实现速度较慢的原因的猜测是因为子例程在每次迭代中都涉及整数除法,而您的子例程只在 return 语句中调用一次除法。

关于python - `scipy.misc.comb` 比临时二项式计算快吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33468821/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com