Angles between two n-dimensional vectors in Python
import math
def dotproduct(v1, v2):
return sum((a*b) for a, b in zip(v1, v2))
def length(v):
return math.sqrt(dotproduct(v, v))
def angle(v1, v2):
return math.acos(dotproduct(v1, v2) / (length(v1) * length(v2)))
Note: this will fail when the vectors have either the same or the opposite direction. The correct implementation is here: https://stackoverflow.com/a/13849249/71522
Fastest way to compute angle between 2D vectors
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. ]]
Calculate the angle between the rows of two matrices in numpy
We could use einsum
to replace the dot-product computations and axis
param for the norm
ones to have a vectorized solution, like so -
def angle_rowwise(A, B):
p1 = np.einsum('ij,ij->i',A,B)
p2 = np.linalg.norm(A,axis=1)
p3 = np.linalg.norm(B,axis=1)
p4 = p1 / (p2*p3)
return np.arccos(np.clip(p4,-1.0,1.0))
We could optimize further and bring in more of einsum
, specifically to compute norms
with it. Hence, we could use it like so -
def angle_rowwise_v2(A, B):
p1 = np.einsum('ij,ij->i',A,B)
p2 = np.einsum('ij,ij->i',A,A)
p3 = np.einsum('ij,ij->i',B,B)
p4 = p1 / np.sqrt(p2*p3)
return np.arccos(np.clip(p4,-1.0,1.0))
Hence, to solve our case to get output in degrees -
out = angle_rowwise(A, B)*180/np.pi
Generating two vectors with a given angle between them
For a given starting vector u
and cosine similarity c
:
- Generate 2 points in n-D space; call them
a
andb
- Project
b
onto the plane orthogonal tou
and containinga
- Subtract
a
from the result to obtain a vector orthogonal tou
; call ith
- Use
[u,h]
as a basis and basic trigonometry to generate the desired vectorv
The above method is dimension-agnostic as it only uses dot products. The resultant vectors {v}
are of unit length and uniformly distributed around u
.
Define vectors and find angles using Python in 3D space?
I think your problem might be how you're defining your vectors. If I do everything exactly like you describe in your question, then I also get a sequence of fluctuating angles:
import pandas as pd
import numpy as np
def ang(u, v):
# see https://stackoverflow.com/a/2827466/425458
c = np.dot(u/np.linalg.norm(u), v/np.linalg.norm(v))
return np.rad2deg(np.arccos(np.clip(c, -1, 1)))
d = ''' x y z
0 0.722950 0.611143 0.154976
1 0.722887 0.611518 0.152955
2 0.722880 0.612001 0.150593
3 0.722910 0.612509 0.148238
4 0.723049 0.613053 0.146069
5 0.723113 0.613583 0.143714
6 0.722763 0.613838 0.141321
7 0.721956 0.613876 0.138467
8 0.721638 0.614167 0.136008
9 0.720665 0.614093 0.133143
10 0.719612 0.613956 0.130317
11 0.718672 0.613882 0.127562
12 0.717771 0.613870 0.124638
13 0.716533 0.613668 0.121512'''
df = pd.read_csv(pd.compat.StringIO(d), sep='\s+')
xyz = df.values
u = np.diff(xyz, axis=0)
head = np.array([0.5806, 0.50239, 0.54057])
tail = np.array([0.5806, 0.50239, 0. ])
v = head - tail
ang(u, v)
# output:
# array([101.96059029, 104.01677172, 103.97438663, 102.85092705,
# 103.97438663, 104.20457158, 107.01708978, 104.604926 ,
# 107.08468905, 106.84512875, 106.40978005, 107.44768844,
# 108.69610224])
However, if you treat your list of xyz
points as vectors (ie the vectors starting at the origin and going to each of the points), then you do see a constantly increasing angle between the reference vector and the sequence of vectors, like you expected:
ang(xyz, v)
# output:
# array([87.51931013, 87.55167997, 87.58951053, 87.62722792, 87.66196546,
# 87.69968089, 87.73800388, 87.78370828, 87.82308596, 87.8689639 ,
# 87.91421599, 87.95832992, 88.0051486 , 88.05520021])
Might this be the actually correct way to interpret/analyze your data?
Related Topics
Python Selenium Chrome Webdriver
Creating a Bat File for Python Script
Failed to Get Convolution Algorithm. This Is Probably Because Cudnn Failed to Initialize,
How to Capture Output of Python's Interpreter and Show in a Text Widget
How to Generate Circular Thumbnails with Pil
Escape Special Characters in a Python String
How to Understand Numpy Strides for Layman
How to Tell If Numpy Creates a View or a Copy
Windows- Pyinstaller Error "Failed to Execute Script " When App Clicked
Adding Meta-Information/Metadata to Pandas Dataframe
How to Display Tooltips in Tkinter
What Is the Maximum Float in Python
How Can One Continuously Generate and Track Several Random Objects with a Time Delay in Pygame