Chapter 3, example 2

This example shows three different ways of creating multiplication tables:

  • one method in pure Python,
  • one method using NumPy,
  • one optimized method using NumPy.

Version 1: Pure Python version

This version uses list comprehensions.


In [1]:
def mul1(n):
    return array([[(i + 1) * (j + 1) for i in xrange(n)] for j in xrange(n)])

In [2]:
mul1(4)


Out[2]:
array([[ 1,  2,  3,  4],
       [ 2,  4,  6,  8],
       [ 3,  6,  9, 12],
       [ 4,  8, 12, 16]])

In [3]:
timeit mul1(100)


100 loops, best of 3: 5.24 ms per loop

Version 2: NumPy version

This version uses array manipulation and operations.


In [4]:
def mul2(n):
    M = arange(1, n + 1).reshape((-1, 1))
    M = tile(M, (1, n))
    N = arange(1, n + 1).reshape((1, -1))
    N = tile(N, (n, 1))
    return M * N

In [5]:
mul2(4)


Out[5]:
array([[ 1,  2,  3,  4],
       [ 2,  4,  6,  8],
       [ 3,  6,  9, 12],
       [ 4,  8, 12, 16]])

In [6]:
timeit mul2(100)


1000 loops, best of 3: 251 us per loop

Using NumPy is about 20 times faster here.

Version 3: Optimized NumPy version

This version is an optimized version of the previous example, using broadcasting instead of unnecessary array tiling.


In [7]:
def mul3(n):
    M = arange(1, n + 1).reshape((-1, 1))
    N = arange(1, n + 1).reshape((1, -1))
    return M * N

In [8]:
mul3(4)


Out[8]:
array([[ 1,  2,  3,  4],
       [ 2,  4,  6,  8],
       [ 3,  6,  9, 12],
       [ 4,  8, 12, 16]])

In [9]:
timeit mul3(100)


10000 loops, best of 3: 88.3 us per loop

This optimized version is about 60 times faster than the original Python version.