Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fastest way to compute angle between 2D vectors

I'm looking for efficient alternate ways to compute cosine angle between 2D vectors. Your insights on this problem will be of much help.

Problem Statement:

vectors is a 2D array where vectors are stored. The shape of the vectors array is (N, 2) where N is the number of vectors. vectors[:, 0] has x-component and vectors[:, 1] has y-component.

I have to find the angle between all the vectors in vectors. For example, if there are three vectors A, B, C in vectors, I need to find the angle between A and B, B and C, and, A and C.

I have implemented it and wants to know alternative ways.

Current Implementation:

vectors = np.array([[1, 3], [2, 4], [3, 5]])

vec_x = vectors[:, 0]
vec_y = vectors[:, 1]

a1 = np.ones([vec_x.shape[0], vec_x.shape[0]]) * vec_x
a2 = np.ones([vec_x.shape[0], vec_x.shape[0]]) * vec_y
a1b1 = a1 * a1.T
a2b2 = a2 * a2.T
mask = np.triu_indices(a1b1.shape[0], 0) # We are interested in lower triangular matrix
a1b1[mask] = 0
a2b2[mask] = 0
numer = a1b1 + a2b2
denom = np.ones([vec_x.shape[0], vec_x.shape[0]]) * np.sqrt(np.square(a1) + np.square(a2))
denom = denom * denom.T
denom[mask] = 0
eps = 1e-7
dot_res = np.rad2deg(np.arccos(np.divide(numer, denom + eps)))
dot_res[mask] = 0
print(dot_res)

Output:

[[ 0.          0.          0.        ]
 [ 8.13010519  0.          0.        ]
 [12.52880911  4.39870821  0.        ]]

Questions:

  1. Is there any alternative way to do this more efficient?

  2. Can we improve the speed of the current version in some way?

like image 323
tpk Avatar asked Jun 17 '19 10:06

tpk


1 Answers

Use scipy.spatial.distance.pdist:

import numpy as np
import scipy.spatial.distance

vectors = np.array([[1, 3], [2, 4], [3, 5]])
# Compute cosine distance
dist = scipy.spatial.distance.pdist(vectors, 'cosine')
# Compute angles
angle = np.rad2deg(np.arccos(1 - dist))
# Make it into a matrix
angle_matrix = scipy.spatial.distance.squareform(angle)
print(angle_matrix)
# [[ 0.          8.13010235 12.52880771]
#  [ 8.13010235  0.          4.39870535]
#  [12.52880771  4.39870535  0.        ]]
like image 61
jdehesa Avatar answered Sep 30 '22 09:09

jdehesa