Factorial in numpy and scipy

How can I import factorial function from numpy and scipy separately in order to see which one is faster?

I already imported factorial from python itself by import math. But, it does not work for numpy and scipy.

211355 次浏览

You can import them like this:

In [7]: import scipy, numpy, math


In [8]: scipy.math.factorial, numpy.math.factorial, math.factorial
Out[8]:
(<function math.factorial>,
<function math.factorial>,
<function math.factorial>)

scipy.math.factorial and numpy.math.factorial seem to simply be aliases/references for/to math.factorial, that is scipy.math.factorial is math.factorial and numpy.math.factorial is math.factorial should both give True.

SciPy has the function scipy.special.factorial (formerly scipy.misc.factorial)

>>> import math
>>> import scipy.special
>>> math.factorial(6)
720
>>> scipy.special.factorial(6)
array(720.0)

The answer for Ashwini is great, in pointing out that scipy.math.factorial, numpy.math.factorial, math.factorial are the same functions. However, I'd recommend use the one that Janne mentioned, that scipy.special.factorial is different. The one from scipy can take np.ndarray as an input, while the others can't.

In [12]: import scipy.special


In [13]: temp = np.arange(10) # temp is an np.ndarray


In [14]: math.factorial(temp) # This won't work
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-14-039ec0734458> in <module>()
----> 1 math.factorial(temp)


TypeError: only length-1 arrays can be converted to Python scalars


In [15]: scipy.special.factorial(temp) # This works!
Out[15]:
array([  1.00000000e+00,   1.00000000e+00,   2.00000000e+00,
6.00000000e+00,   2.40000000e+01,   1.20000000e+02,
7.20000000e+02,   5.04000000e+03,   4.03200000e+04,
3.62880000e+05])

So, if you are doing factorial to a np.ndarray, the one from scipy will be easier to code and faster than doing the for-loops.

    from numpy import prod


def factorial(n):
print prod(range(1,n+1))

or with mul from operator:

    from operator import mul


def factorial(n):
print reduce(mul,range(1,n+1))

or completely without help:

    def factorial(n):
print reduce((lambda x,y: x*y),range(1,n+1))

You can save some homemade factorial functions on a separate module, utils.py, and then import them and compare the performance with the predefinite one, in scipy, numpy and math using timeit. In this case I used as external method the last proposed by Stefan Gruenwald:

import numpy as np




def factorial(n):
return reduce((lambda x,y: x*y),range(1,n+1))

Main code (I used a framework proposed by JoshAdel in another post, look for how-can-i-get-an-array-of-alternating-values-in-python):

from timeit import Timer
from utils import factorial
import scipy


n = 100


# test the time for the factorial function obtained in different ways:


if __name__ == '__main__':


setupstr="""
import scipy, numpy, math
from utils import factorial
n = 100
"""


method1="""
factorial(n)
"""


method2="""
scipy.math.factorial(n)  # same algo as numpy.math.factorial, math.factorial
"""


nl = 1000
t1 = Timer(method1, setupstr).timeit(nl)
t2 = Timer(method2, setupstr).timeit(nl)


print 'method1', t1
print 'method2', t2


print factorial(n)
print scipy.math.factorial(n)

Which provides:

method1 0.0195569992065
method2 0.00638914108276


93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000




Process finished with exit code 0

enter image description here

after running different aforementioned functions for factorial, by different people, turns out that math.factorial is the fastest to calculate the factorial.

find running times for different functions in the attached image