31 votes

`Scipy.misc.comb` est-il plus rapide qu'un calcul binomial ad hoc?

Est-il concluant que maintenant l' scipy.misc.comb est en effet plus rapide que le ad-hoc mise en œuvre?

Selon une vieille réponse, les Statistiques: les combinaisons en Python, ce homebrew fonction est plus rapide que l' scipy.misc.comb lors du calcul de combinaisons nCr:

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

Mais après l'exécution de certains tests sur ma machine, cela ne semble pas être le cas, à l'aide de ce script:

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)

J'obtiens le résultat suivant:

$ 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

N'a le temps de test de profil montrent que le nouveau scipy.misc.comb est plus rapide que le ad-hoc choose() fonction? Est-il une erreur de mon script de test qui rend le moment inexactes?

Pourquoi est-ce que l' scipy.misc.comb est plus rapide maintenant? C'est à cause de certains cython / c emballage astuces?


ÉDITÉ

Après @WarrenWeckesser commentaire:

À l'aide de la valeur par défaut de point flottant de rapprochement lors de l'utilisation d' scipy.misc.comb(), le calcul des pauses à cause de la virgule flottante de débordement.

(voir http://docs.scipy.org/doc/scipy-0.16.0/reference/generated/scipy.misc.comb.html pour la documentation)

Lorsqu'il est testé avec exact=True qui calcule avec des entiers longs au lieu de la virgule flottante à l'aide de la fonction ci-dessous, c'est beaucoup plus lent lors du calcul de 1000 combinaisons:

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

[out]:

$ 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

1voto

Victor Points 11

Se référant au code source de scipy.misc.peigne, la routine de mise à jour de la suite est:

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

alors que la routine de mise à jour que vous avez suggéré est:

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

Je suppose que la raison pour laquelle SciPy de la mise en œuvre est plus lente, en raison du fait que la sous-routine implique une division entière à chaque itération, tandis que la vôtre seuls les appels de la division une fois à l'instruction de retour.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X