**Broadcasting With NumPy**

Pages: 1, **2**, 3

### Multiarray and multiarray

Scalars are simple enough. Let's move on to more complex operations where we have two multiarrays.

In the next example we have equivalent rank, but the length of each dimension does not agree.

`>>> `**a**
array([[1, 2, 3],
[4, 5, 6]])
>>> **b**
array([[1, 2],
[3, 4],
[5, 6]])
>>> **a+b**
Traceback (innermost last):
File "<stdin>", line 1, in ?
ValueError: frames are not aligned

We get the dreaded "frames not aligned" error. This was caused by `a`

being a 2-by-3 multiarray and `b`

being a 3-by-2 multiarray.

Let's try another multiarray example.

`>>> `**a**
array([[1, 2, 3],
[4, 5, 6]])
>>> **c**
array([7, 8, 9])
>>> **a+c**
array([[ 8, 10, 12],
[11, 13, 15]])

OK, so why did this one work when the length of the dimensions did not match? This is another example of broadcasting. The `a`

array is of rank 2 and `c`

is of rank one. In this case the size of each individual dimension (or axis) is compared, and under certain conditions the lower rank array is replicated. To gain insight, let's look at the shape tuple for both `a`

and `c`

. Remember the `.shape`

attribute returns the tuple defining the rank (the length of the tuple) and the length of each axis (the values in the tuple).

`>>> `**a.shape**
(2, 3)
>>> **c.shape**
(3,)

When two multiarrays of differing rank are operated on, the length of each axis is compared starting from the right-most. Since the lowest (right-most) axis for both `a`

and `c`

is three, we are in business. When `c`

is broadcast, it is essentially replicated as many times as necessary to match the upper dimensions of `a`

, in this case two. This methodology also holds for objects whose rank is greater than one or two.

In the next and following examples, we will use the `zeros()`

function to create multiarrays of a given shape. Yes, you guessed it, filled with zeros! For the purpose of our discussions, we are not particular about the values in the multiarray -- rather, we are interested in the shape of the object. The `zeros()`

function provides a simple, convenient way for generating multiarrays of the desired shape.

`>>> `**x=zeros((3,4,5,6,7))**
>>> **y=zeros((7,))**
>>> **z=x+y**

In this example we created a rank five multiarray `x`

and a rank one multiarray `y`

. When the addition operator tried to add these together, it needed to broadcast the `y`

multiarray across the `x`

multiarray, essentially replicating as many times as necessary. In this case the four higher axes were "created" for the `y`

multiarray.

Just to throw in a twist, there is an exception to the above discussion. When comparing the size of each axis, if either one of the compared axes has a size of one, broadcasting can also occur. As an example

`>>> `**z**
array([1, 2])
>>> **z.shape**
(2,)
>>> **v**
array([[3],
[4],
[5]])
>>> **v.shape**
(3, 1)
>>> **z+v**
array([[4, 5],
[5, 6],
[6, 7]])

In this form, the first multiarray `z`

was extended to a (3,2) multiarray and the second multiarray `v`

was extended to a (3,2) multiarray. Essentially, broadcasting occurred on both operands! This only occurs when the axis size of one of the multiarrays has the value of one.