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

Posted

技术标签:

【中文标题】`scipy.misc.comb` 比临时二项式计算快吗?【英文标题】:Is `scipy.misc.comb` faster than an ad-hoc binomial computation? 【发布时间】:2016-02-01 19:36:35 【问题描述】:

现在scipy.misc.comb 确实比 ad-hoc 实现更快,是否有结论?

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

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 比专用的choose() 函数更快?我的测试脚本中是否有任何错误导致计时不准确? p>

为什么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 进行测试时,使用下面的函数使用长整数而不是浮点数进行计算,计算 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 的comb 计算一个浮点值,当参数足够大时,这将是一个近似值。您应该使用comb 中的参数exact=True 比较时间。 哇,在使用exact=True 之后,速度超级慢。那么有什么理由不使用临时功能而不是scipy.misc.comb 好问题!如果你觉得有动力,你可以添加任何与 github.com/scipy/scipy/issues/3449 相关的 cmets 【参考方案1】:

参考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 语句中调用一次除法。

【讨论】:

以上是关于`scipy.misc.comb` 比临时二项式计算快吗?的主要内容,如果未能解决你的问题,请参考以下文章

什么是切比雪夫多项式?

什么是切比雪夫多项式?它有什么重要性质

切比雪夫多项式的马尔科夫定理的证明?

2017西安网络赛 计蒜客 Trig Function 切比雪夫多项式

算法导论 二项堆

请问在高中数学里求最值是如何运用切比雪夫多项式的。