1

So I am trying to vectorize this code in numpy and im having trouble Heres is my for loop version which works as desired:

B is a 3x3 Matrix

 for i in range(b.shape[0]):  
    for j in range(b.shape[0]):
       Z[i,j] = np.sqrt(np.dot((b[i,:].T - b[j,:].T).T  ,  b[i,:].T - b[j,:].T))

Now I am trying to vectorized this code so I dont have to use a double for loop. Here what I have gotten so far which does not work:

i = 0, j = 0
np.sqrt( np.dot ( (p[i,:].T - p[j:,:].T).T  , p[i,:].T - p[j,:].T ))

Ideally it should perform this if you break down to what a for loop would do.

np.sqrt( np.dot ( (p[0,:].T - p[0,:].T).T  ,  p[0,:].T - p[0,:].T  ))
np.sqrt( np.dot ( (p[0,:].T - p[1,:].T).T  ,  p[0,:].T - p[1,:].T  )) 
np.sqrt( np.dot ( (p[1,:].T - p[0,:].T).T  ,  p[1,:].T - p[0,:].T  ))
np.sqrt( np.dot ( (p[1,:].T - p[1,:].T).T  ,  p[1,:].T - p[1,:].T  ))

Can someone kindly provide some insight. I would prefer not to use any built in functions and stick to using things like np.dot. Btw this is to compute the Eucledean distance matrix.

bluemoon718
  • 139
  • 1
  • 1
  • 5

1 Answers1

3

You can vectorize it as:

b = np.asarray(b)                      # in case you have a matrix, convert it to an array
np.linalg.norm(b - b[:,None], axis=2)

b - b[:,None] does a row wise outer subtraction of b, and np.sqrt(np.dot(...,...)) can be calculated with np.linalg.norm.


Example:

a = np.arange(9).reshape(3,3)
b = np.matrix(a)

Z = np.zeros_like(b, dtype=np.float32)


for i in range(b.shape[0]):  
    for j in range(b.shape[0]):
        Z[i,j] = np.sqrt(np.dot((b[i,:].T - b[j,:].T).T  ,  b[i,:].T - b[j,:].T))

Z
#array([[  0.        ,   5.19615221,  10.39230442],
#       [  5.19615221,   0.        ,   5.19615221],
#       [ 10.39230442,   5.19615221,   0.        ]], dtype=float32)

b = np.asarray(b) 
np.linalg.norm(b - b[:,None], axis=2)
#array([[  0.        ,   5.19615242,  10.39230485],
#       [  5.19615242,   0.        ,   5.19615242],
#       [ 10.39230485,   5.19615242,   0.        ]])
Psidom
  • 209,562
  • 33
  • 339
  • 356