IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
5.3 Pseudo Indices

5.3 Pseudo Indices

This section discusses pseudo-indices, which allow arrays to have their shapes modified by adding axes, sometimes only for the duration of the evaluation of a Python expression.

Consider multiplication of a rank-1 array by a scalar:

>>> a = array([1,2,3])
>>> print a * 2
[2 4 6]
This should be trivial by now; we've just multiplied a rank-1 array by a scalar . The scalar was converted to a rank-0 array which was then broadcast to the next rank. This works for adding some two rank-1 arrays as well:
>>> print a
[1 2 3]
>>> a + array([4])
[5 6 7]
but it won't work if either of the two rank-1 arrays have non-matching dimensions which aren't 1. In other words, broadcast only works for dimensions which are either missing (e.g. a lower-rank array) or for dimensions of 1.

With this in mind, consider a classic task, matrix multiplication. Suppose we want to multiply the row vector [10,20] by the column vector [1,2,3].

>>> a = array([10,20])
>>> b = array([1,2,3])
>>> a * b
ValueError: Arrays have incompatible shapes
This makes sense: we're trying to multiply a rank-1 array of shape (2,) with a rank-1 array of shape (3,). This violates the laws of broadcast. What we really want to do is make the second vector a vector of shape (3,1), so that the first vector can be broadcast across the second axis of the second vector. One way to do this is to use the reshape function:
>>> a.getshape()
(2,)
>>> b.getshape()
(3,)
>>> b2 = reshape(b, (3,1))
>>> print b2
[[1]
 [2]
 [3]]
>>> b2.getshape()
(3, 1)
>>> print a * b2    # Note: b2 * a gives the same result
[[10 20]
 [20 40]
 [30 60]]
This is such a common operation that a special feature was added (it turns out to be useful in many other places as well) - the NewAxis "pseudo-index", originally developed in the Yorick language. NewAxis is an index, just like integers, so it is used inside of the slice brackets []. It can be thought of as meaning "add a new axis here," in much the same ways as adding a 1 to an array's shape adds an axis. Again, examples help clarify the situation:
>>> print b
[1 2 3]
>>> b.getshape()
(3,)
>>> c = b[:, NewAxis]
>>> print c
[[1]
 [2]
 [3]]
>>> c.getshape()
(3,1)
Why use such a pseudo-index over the reshape function or setshape assignments? Often one doesn't really want a new array with a new axis, one just wants it for an intermediate computation. Witness the array multiplication mentioned above, without and with pseudo-indices:
>>> without = a * reshape(b, (3,1))
>>> with = a * b[:,NewAxis]
The second is much more readable (once you understand how NewAxis works), and it's much closer to the intended meaning. Also, it's independent of the dimensions of the array b. You might counter that using something like reshape(b, (-1,1)) is also dimension-independent, but it's less readable and impossible with rank-3 or higher arrays? The NewAxis-based idiom also works nicely with higher rank arrays, and with the ... "rubber index" mentioned earlier. Adding an axis before the last axis in an array can be done simply with:
>>> a[...,NewAxis,:]
Note that NewAxis is a numarray object, so if you used import numarray instead of from numarray import *, you'll need numarray.NewAxis.

Send comments to the NumArray community.