Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Numpy Array Broadcasting with different dimensions

Tags:

python

numpy

I a little confused by the broadcasting rules of numpy. Suppose you want to perform an axis-wise scalar product of a higher dimension array to reduce the array dimension by one (basically to perform a weighted summation along one axis):

from numpy import *

A = ones((3,3,2))
v = array([1,2])

B = zeros((3,3))

# V01: this works
B[0,0] = v.dot(A[0,0])

# V02: this works
B[:,:] = v[0]*A[:,:,0] + v[1]*A[:,:,1] 

# V03: this doesn't
B[:,:] = v.dot(A[:,:]) 

Why does V03 not work?

Cheers

like image 868
cp3028 Avatar asked Mar 08 '13 15:03

cp3028


People also ask

Can you broadcast more than one dimension?

Broadcasting Rules: The two arrays are compatible in a dimension if they have the same size in the dimension or if one of the arrays has size 1 in that dimension. The arrays can be broadcast together iff they are compatible with all dimensions.

Can you add arrays with different dimensions?

The arrays must have the same shape, except in the dimension corresponding to axis (the first, by default). The axis along which the arrays will be joined.

Can NumPy arrays be multidimensional?

In general numpy arrays can have more than one dimension. One way to create such array is to start with a 1-dimensional array and use the numpy reshape() function that rearranges elements of that array into a new shape.

Which of the following dimension supports broadcasting of two arrays of different size?

If the dimensions of two arrays are dissimilar, element-to-element operations are not possible. However, operations on arrays of non-similar shapes is still possible in NumPy, because of the broadcasting capability. The smaller array is broadcast to the size of the larger array so that they have compatible shapes.


1 Answers

np.dot(a, b) operates over the last axis of a and the second-to-last of b. So for your particular case in your question,you could always go with :

>>> a.dot(v)
array([[ 3.,  3.,  3.],
       [ 3.,  3.,  3.],
       [ 3.,  3.,  3.]])

If you want to keep the v.dot(a) order, you need to get the axis into position, which can easily be achieved with np.rollaxis:

>>> v.dot(np.rollaxis(a, 2, 1))
array([[ 3.,  3.,  3.],
       [ 3.,  3.,  3.],
       [ 3.,  3.,  3.]])

I don't like np.dot too much, unless it is for the obvious matrix or vector multiplication, because it is very strict about the output dtype when using the optional out parameter. Joe Kington has mentioned it already, but if you are going to be doing this type of things, get used to np.einsum: once you get the hang of the syntax, it will cut down the amount of time you spend worrying about reshaping things to a minimum:

>>> a = np.ones((3, 3, 2))
>>> np.einsum('i, jki', v, a)
array([[ 3.,  3.,  3.],
       [ 3.,  3.,  3.],
       [ 3.,  3.,  3.]])

Not that it is too relevant in this case, but it is also ridiculously fast:

In [4]: %timeit a.dot(v)
100000 loops, best of 3: 2.43 us per loop

In [5]: %timeit v.dot(np.rollaxis(a, 2, 1))
100000 loops, best of 3: 4.49 us per loop

In [7]: %timeit np.tensordot(v, a, axes=(0, 2))
100000 loops, best of 3: 14.9 us per loop

In [8]: %timeit np.einsum('i, jki', v, a)
100000 loops, best of 3: 2.91 us per loop
like image 169
Jaime Avatar answered Nov 11 '22 02:11

Jaime