Hide code cell source
import numpy as np

Array algebra#

‘numpy’ makes matrix algebra very easy (minimal code) and fast. Consider two vectors, \(x\) and \(y\) and we wish to subtract \(y\) from \(x\).

numpy code for this type of mathematical operation is extremely simple and readable.

x = np.array([10, 20, 30, 40])
y = np.array([10, 10, 10, 10])

z = x - y 

print(z)
[ 0 10 20 30]
x = np.array([10, 20, 30, 40], dtype=np.int64)
y = x + 5
z = y ** 2

print(z)
[ 225  625 1225 2025]

Broadcasting#

We have already seen that numpy can elegantly handle an element wise addition using the following syntax:

x = np.array([10, 20, 30, 40])
y = x + 5

numpy achieves this via a technique called broadcasting. In effect numpy stretched the scalar value 5 into an array with dimensions compatable with x:

x = np.array([10, 20, 30, 40])
y = x + np.array([5, 5, 5, 5])
x = np.array([10, 20, 30, 40])
y = x + np.array([5, 5, 5, 5])
y
array([15, 25, 35, 45])

Broadcasting works for different sized arrays a well as scalars. The numpy docs specifies the following broad casting rule:

In order to broadcast, the size of the trailing axes for both arrays in an operation must either be the same size or one of them must be one.

We have already seen an example where the trailing axes is one above. Here’s a more complex example:

a = np.array([[ 0,  1,  2],
              [ 3,  4,  5],
              [ 6,  7,  8],
              [ 9, 10, 11]])

b = np.array([1,  2, 3])

a + b
array([[ 1,  3,  5],
       [ 4,  6,  8],
       [ 7,  9, 11],
       [10, 12, 14]])

This is equivalent to the following matrix addition where b is stretched

a = np.array([[ 0,  1,  2],
              [ 3,  4,  5],
              [ 6,  7,  8],
              [ 9, 10, 11]])

b = np.array([[ 1,  2,  3],
              [ 1,  2,  3],
              [ 1,  2,  3],
              [ 1,  2,  3]])

a + b
array([[ 1,  3,  5],
       [ 4,  6,  8],
       [ 7,  9, 11],
       [10, 12, 14]])

Note that we were able to broadcast in this instance because of the dimensions of the arrays

a = np.array([[ 0,  1,  2],
              [ 3,  4,  5],
              [ 6,  7,  8],
              [ 9, 10, 11]])

b = np.array([1, 2, 3])

print(a.shape)
print(b.shape)
(4, 3)
(3,)

We can break numpy broadcasting rules if, for example, b were a lost a column.

a = np.array([[ 0,  1,  2],
              [ 3,  4,  5],
              [ 6,  7,  8],
              [ 9, 10, 11]])

b = np.array([1, 2])

print(a.shape)
print(b.shape)

a + b
(4, 3)
(2,)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-20-bc2a4615e61a> in <module>
      9 print(b.shape)
     10 
---> 11 a + b

ValueError: operands could not be broadcast together with shapes (4,3) (2,)