Factorials – NumPy, Scipy, Math, Python

Factorial Definition and Example

πŸ’‘ The factorial function n! calculates the number of permutations in a set.

Say you want to rank three soccer teams Manchester United, FC Barcelona, and FC Bayern MΓΌnchen — how many possible rankings exist?

The answer is 3! = 3 x 2 x 1 = 6.

Practical Example: Say, there are 20 football teams in England’s premier league. Each team can possibly reach any of the 20 ranks at the end of the season. How many possible rankings exist in the premier league, given 20 fixed teams?

Figure: Example of three possible rankings of the football teams in England’s premier league.

In general, to calculate the factorial n!, you need to multiply all positive integer numbers that are smaller or equal to n.

For example, if you have 5 soccer teams, there are 5! = 5 x 4 x 3 x 2 x 1 = 120 different pairings.

There are many different ways to calculate the factorial function in Python easily, see alternatives below.

Feel free to watch my explainer video as you go through the article:

How to Calculate the Factorial in NumPy?

NumPy’s math module contains efficient implementations of basic math functions such as the factorial function numpy.math.factorial(n).

Here’s an example of how to calculate the factorial 3! with NumPy:

>>> import numpy as np
>>> np.math.factorial(3)
6

The factorial function in NumPy has only one integer argument n. If the argument is negative or not an integer, Python will raise a value error.

Here’s how you can calculate this in Python for 3 teams:

Exercise: Modify the code to calculate the number of rankings for 20 teams!

How to Calculate the Factorial in Scipy?

The popular scipy library is a collection of libraries and modules that help you with scientific computing.

Scipy contains a powerful collection of functionality—built upon the NumPy library. Thus, it doesn’t surprise that the SciPy factorial function scipy.math.factorial() is actually a reference to NumPy’s factorial function numpy.math.factorial().

In fact, if you compare their memory addresses using the keyword is, it turns out that both refer to the same function object:

>>> import scipy, numpy
>>> scipy.math.factorial(3)
6
>>> numpy.math.factorial(3)
6
>>> scipy.math.factorial is numpy.math.factorial
True

So you can use both scipy.math.factorial(3) and numpy.math.factorial(3) to compute the factorial function 3!.

As both functions point to the same object, the performance characteristics are the same — one is not faster than the other one.

Let’s have a look at math.factorial() — the mother of all factorial functions. πŸ˜‰


Check out my new Python book Python One-Liners (Amazon Link).

If you like one-liners, you’ll LOVE the book. It’ll teach you everything there is to know about a single line of Python code. But it’s also an introduction to computer science, data science, machine learning, and algorithms. The universe in a single line of Python!

The book was released in 2020 with the world-class programming book publisher NoStarch Press (San Francisco).

Publisher Link: https://nostarch.com/pythononeliners

How to Calculate the Factorial in Python’s Math Library?

As it turns out, not only NumPy and Scipy come with a packaged “implementation” of the factorial function, but also Python’s powerful math library.

You can use the math.factorial(n) function to compute the factorial n!.

Here’s an example:

>>> import math
>>> math.factorial(3)
6

The factorial of 3 is 6 — nothing new here.

Let’s check whether this is actually the same implementation as NumPy’s and Scipy’s factorial functions:

>>> import scipy, numpy, math
>>> scipy.math.factorial is math.factorial
True
>>> numpy.math.factorial is math.factorial
True

Ha! Both libraries NumPy and Scipy rely on the same factorial function of the math library.

πŸ’‘ Note: Hence, to save valuable space in your code, use the math factorial function if you have already imported the math library. If not, just use the NumPy or Scipy factorial function aliases.

So up ’till now we’ve seen the same old wine in three different bottles: NumPy, Scipy, and math libraries all refer to the same factorial function implementation.

How to Calculate the Factorial in Python?

It’s often a good idea to implement a function by yourself. This will help you understand the underlying details better and gives you confidence and expertise.

So let’s implement the factorial function in Python!

To calculate the number of permutations of a given set of n elements, you use the factorial function n!. The factorial is defined as follows:

n! = n Γ— (n – 1) Γ— ( n – 2) Γ— . . .  Γ— 1

For example:

  • 1! = 1
  • 3! = 3 Γ— 2 Γ— 1 = 6
  • 10! = 10 Γ— 9 Γ— 8 Γ— 7 Γ— 6 Γ— 5 Γ— 4 Γ— 3 Γ— 2 Γ— 1 = 3,628,800
  • 20! = 20 Γ— 19 Γ— 18 Γ— . . .  Γ— 3 Γ— 2 Γ— 1 = 2,432,902,008,176,640,000

Recursively, the factorial function can also be defined as follows:

n! = n Γ— (n – 1)!

The recursion base cases are defined as shown here:

1! = 0! = 1

The intuition behind these base cases is that a set with one element has one permutation, and a set with zero elements has one permutation (there is one way of assigning zero elements to zero buckets).

Now, we can use this recursive definition to calculate the factorial function in a recursive manner:

>>> factorial = lambda n: n * factorial(n-1) if n > 1 else 1
>>> factorial(3)
6

Try It Yourself: Run this one-liner in our interactive code shell:

Exercise: What’s the output?

The lambda keyword is used to define an anonymous function in a single line.

🌍 Learning Resource: You can learn everything you need to know about the lambda function in this comprehensive tutorial on the Finxter blog.

If you love one-liners like I do, check out my book “Python One-Liners” which will teach you everything there is to learn about a single line of Python code!

You create a lambda function with one argument n and assign the lambda function to the name factorial. Finally, you call the named function factorial(n-1) to calculate the result of the function call factorial(n).

Roughly speaking, you can use the simpler solution for factorial(n-1) to construct the solution of the harder problem factorial(n) by multiplying the former with the input argument n.

As soon as you reach the recursion base case n <= 1, you simply return the hard-coded solution factorial(1) = factorial(0) = 1.

An alternative is to use the iterative computation like this:

def factorial(n):
    fac = n
    for i in range(1, n):
        fac *= i
    return fac

print(factorial(3))
# 6

print(factorial(5))
# 120

In the function factorial(n), we initialize the variable fac to the value n. Then, we iterate over all values i between 1 and n-1 (inclusive) and multiply them with the value currently stored in the variable fac. The result is the factorial of the integer value n.

Speed Comparison

Let’s compare all three different ways to calculate the factorial function regarding speed.

Note that the NumPy, Scipy, and math factorial functions are referencing the same function object—they have the same speed properties.

Thus, we only compare the math.factorial() function with our two implementations in Python (recursive and iterative).

Want to take a guess first?

I used my own notebook computer (Quadcore, Intel Core i7, 8th Generation) with Python 3.7 to run 900 factorial computations for each method using the following code:

import time

num_runs = 900
speed = []


## SPEED TEST MATH.FACTORIAL ##
import math


start = time.time()
for i in range(num_runs):
    math.factorial(i)
stop = time.time()

speed.append(stop-start)

    
## SPEED TEST RECURSIVE ##
factorial = lambda n: n * factorial(n-1) if n > 1 else 1

start = time.time()
for i in range(num_runs):
    factorial(i)
stop = time.time()

speed.append(stop-start)

    
## SPEED TEST ITERATIVE ##
def factorial(n):
    fac = n
    for i in range(1, n):
        fac *= i
    return fac


start = time.time()
for i in range(num_runs):
    factorial(i)
stop = time.time()

speed.append(stop-start)


## RESULT
print(speed)
# [0.011027336120605469, 0.10074210166931152, 0.0559844970703125]
import matplotlib.pyplot as plt
plt.bar(["Math", "Recursive", "Iterative"], height=speed)
plt.show()

Wow—the clear winner is the math module! A clear sign that you should always prefer library code over your own implementations!

The math library’s implementation is almost 600% faster than the iterative one and 1000% faster than the recursive implementation.

Methodmath.factorialRecursiveIterative
Seconds0.010.100.05

Try It Yourself: You can perform this speed comparison yourself in the interactive code shell:

Exercise: Do you receive similar results in your browser? Run the shell to find out!

Where to Go From Here

The three library implementations numpy.math.factorial(), scipy.math.factorial(), and math.factorial() point to the same function object in memory—they are identical so use any of them.

One a higher-level, you’ve learned that library implementations of popular libraries such as NumPy are blazingly fast and efficient. Do yourself a favor and use library implementations wherever possible.

A good place to start is the NumPy library which is the basis of many more advanced data science and machine learning libraries in Python such as matplotlib, pandas, tensorflow, and scikit-learn. Learning NumPy will set the foundation on which you can build your Python career.

🌍 Tutorial: NumPy — Everything you need to know to get started

Programmer Humor

Q: How do you tell an introverted computer scientist from an extroverted computer scientist?

A: An extroverted computer scientist looks at your shoes when he talks to you.