Czy jest przekonujące, że teraz scipy.misc.comb
jest rzeczywiście szybszy niż implementacja ad-hoc?Czy `scipy.misc.comb` jest szybszy niż obliczanie dwumianowe ad-hoc?
Według starej odpowiedź, Statistics: combinations in Python ten homebrew funkcja jest szybszy niż scipy.misc.comb
kiedy liczące kombinacje 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
ale po uruchomione pewne testy na moim komputerze, to nie wydaje się sprawy za pomocą tego skryptu:
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)
uzyskać następujące dane wyjściowe:
$ 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
Czy test profilowania czasu wykazał, że nowy scipy.misc.comb
jest szybszy niż funkcja ad-hoc choose()
? Czy wystąpił błąd w moim skrypcie testowym, który powoduje, że czas jest niedokładny?
Dlaczego teraz scipy.misc.comb
jest szybszy? To z powodu niektórych sztuczek owijających cython
/c
?
EDITED
Po @WarrenWeckesser komentarza:
Korzystanie z domyślnego zmiennoprzecinkowych przybliżenie podczas korzystania scipy.misc.comb()
, przerwy obliczeń zmiennoprzecinkowych z powodu przepełnienia.
(patrz http://docs.scipy.org/doc/scipy-0.16.0/reference/generated/scipy.misc.comb.html dla dokumentacji)
Kiedy testowane exact=True
który oblicza z długich liczb całkowitych zamiast zmiennoprzecinkowych użyciu funkcji poniżej, jest to o wiele wolniej przy obliczaniu 1000 kombinacje:
@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
Domyślnie "comb" scipy oblicza wartość zmiennoprzecinkową, która będzie przybliżeniem, gdy argumenty będą wystarczająco duże. Powinieneś porównać czas używając argumentu 'exact = True' w' comb'. –
Wow, po użyciu 'exact = True' jest bardzo wolny. Czy istnieje jakikolwiek powód, aby nie używać funkcji ad-hoc zamiast 'scipy.misc.comb' – alvas
Dobre pytanie! Jeśli czujesz się zmotywowany, możesz dodać komentarze, które wydają się istotne dla https: // github.com/scipy/scipy/issues/3449 –