views:

507

answers:

2

How can a list of vectors be elegantly normalized, in NumPy?

Here is an example that does not work:

from numpy import *

vectors = array([arange(10), arange(10)])  # All x's, then all y's
norms = apply_along_axis(linalg.norm, 0, vectors)

# Now, what I was expecting would work:
print vectors.T / norms  # vectors.T has 10 elements, as does norms, but this does not work

The last operation yields "shape mismatch: objects cannot be broadcast to a single shape".

How can the normalization of the 2D vectors in vectors be elegantly done, with NumPy?

Edit: Why does the above not work while adding a dimension to norms does work (as per my answer below)?

+1  A: 

Alright: NumPy does not broadcast automatically, but can be instructed to do so by adding a dimension to the norms array:

print vectors.T / norms[:, newaxis]

does work!

EOL
+3  A: 

Well, unless I missed something, this does work:

vectors / norms

The problem in you suggestion is the broadcasting rules.

vectors # shape 2, 10
norms # shape 10

The shape do not have the same length! So the rule is to first extend the small shape by one on the left:

norms # shape 1,10

You can do that manually by calling:

vectors / norms.reshape(1,-1) # same as vectors/norms

If you wanted to compute vectors.T/norms, you would have to do the reshaping manually, as follows:

vectors.T / norms.reshape(-1,1) # this works
Olivier
why not just do (vectors/norms).T if the OP wants this transposed. It seems both simple and elegant to me.
Justin Peel
Ah, ah! so the dimension extension is done on the _left_: this indeed explains the observed behavior. Thanks!
EOL