6

I have a numpy array of 2D vectors, which I am trying to normalize as below. The array can have vectors with magnitude zero.

x = np.array([[0.0, 0.0], [1.0, 0.0]])
norms = np.array([np.linalg.norm(a) for a in x])

>>> x/norms
array([[ nan,   0.],
       [ inf,   0.]])

>>> nonzero = norms > 0.0
>>> nonzero
array([False,  True], dtype=bool)

Can I somehow use nonzero to apply the division only to x[i] such that nonzero[i] is True? (I can write a loop for this - just wondering if there's a numpy way of doing this)

Or is there a better way of normalizing the array of vectors, skipping all zero vectors in the process?

M-V
  • 5,167
  • 7
  • 52
  • 55
  • `np.linalp.norm` has a second argument `axis` you can use to increase speed, as discussed here: http://stackoverflow.com/a/19794741/1959808 – 0 _ Nov 18 '13 at 09:10

3 Answers3

7

If you can do the normalization in place, you can use your boolean indexing array like this:

nonzero = norms > 0
x[nonzero] /= norms[nonzero]
Jaime
  • 65,696
  • 17
  • 124
  • 159
2

Here's one possible way of doing this

norms = np.sqrt((x**2).sum(axis=1,keepdims=True))
x[:] = np.where(norms!=0,x/norms,0.)

This uses np.where to do the substitution you need.

Note: in this case x is modified in place.

IanH
  • 10,250
  • 1
  • 28
  • 32
  • 1
    +1 Beat me toit by a few seconds! To do it in place I think it is better to use a boolean indexing array: `idx = (norms != 0); x[idx] /= norms[idx]` – Jaime Jul 21 '13 at 05:57
  • @Jaime - thanks! Please post it as an answer so I can give you credit. – M-V Jul 21 '13 at 06:21
1

It's probably easiest just to do the calculation and then modify the results to be what you'd like:

y = x/norms
y[np.isnan(y) | np.isinf(y)]=0

#y = array([[ 0.,  0.],
#       [ 0.,  0.]])
tom10
  • 67,082
  • 10
  • 127
  • 137