python,向量之间的角度:计算效率的需要
我有超过500万对的两个3D向量,我需要计算每对向量之间的角度。 我试过:python,向量之间的角度:计算效率的需要,python,performance,loops,math,angle,Python,Performance,Loops,Math,Angle,我有超过500万对的两个3D向量,我需要计算每对向量之间的角度。 我试过: # calculate angle def unit_vector(vector): return vector / np.linalg.norm(vector) def angle_between(v1, v2): v1_u = unit_vector(v1) v2_u = unit_vector(v2) return np.arccos(np.clip(np.dot(v1_u, v
# calculate angle
def unit_vector(vector):
return vector / np.linalg.norm(vector)
def angle_between(v1, v2):
v1_u = unit_vector(v1)
v2_u = unit_vector(v2)
return np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0))
如
例如:
a=[[1,1,1],[1,2,1],[6,4,5]]
b=[[1,0,0],[6,2,2],[1,9,2]]
anglevec=np.zeros(len(a))
for i in range(len(a)):
anglevec[i]=angle_between(a[i], b[i])
print(anglevec)
但是循环的实现太慢了
有人能帮忙吗?这里有一个使用Pool和Pool.map的解决方案
from multiprocessing import Pool, cpu_count
import numpy as np
def unit_vector(vector):
return vector / np.linalg.norm(vector)
def angle_between(v1, v2):
#if you want to maximize speed, avoid making variables
#v1_u = unit_vector(v1)
#v2_u = unit_vector(v2)
return np.arccos(np.clip(np.dot(unit_vector(v1_u),unit_vector(v2_u)),-1.0,1.0))
def calc_angle(_list):
#use list unpacking instead of instantiate variables
return angle_between(*_list)
a=[[1,1,1],[1,2,1],[6,4,5]]
b=[[1,0,0],[6,2,2],[1,9,2]]
with Pool(cpu_count()) as p: #use the context manager
angles = p.map(calc_angle, zip(a,b))
输出:
>>> angles
[0.9553166181245092, 0.7398807743787404, 0.8775836986593762]
这里是一个使用Pool和Pool.map的解决方案
from multiprocessing import Pool, cpu_count
import numpy as np
def unit_vector(vector):
return vector / np.linalg.norm(vector)
def angle_between(v1, v2):
#if you want to maximize speed, avoid making variables
#v1_u = unit_vector(v1)
#v2_u = unit_vector(v2)
return np.arccos(np.clip(np.dot(unit_vector(v1_u),unit_vector(v2_u)),-1.0,1.0))
def calc_angle(_list):
#use list unpacking instead of instantiate variables
return angle_between(*_list)
a=[[1,1,1],[1,2,1],[6,4,5]]
b=[[1,0,0],[6,2,2],[1,9,2]]
with Pool(cpu_count()) as p: #use the context manager
angles = p.map(calc_angle, zip(a,b))
输出:
>>> angles
[0.9553166181245092, 0.7398807743787404, 0.8775836986593762]
麻木的方法
这项任务很容易实现。
唯一的问题是Python循环非常慢。这可以通过使用Numba或Cython来避免
示例
import numba as nb
import numpy as np
#You can disable parallelization with parallel=False
@nb.njit(fastmath=True,error_model="numpy",parallel=True)
def angle(v1,v2):
#Check the dimensions, this may also have an effect on SIMD-vectorization
assert v1.shape[1]==3
assert v2.shape[1]==3
res=np.empty(v1.shape[0])
for i in nb.prange(v1.shape[0]):
dot=0.
a=0.
b=0.
for j in range(3):
dot+=v1[i,j]*v2[i,j]
a+=v1[i,j]**2
b+=v2[i,j]**2
res[i]=np.arccos(dot/(np.sqrt(a*b)))
return res
计时
#Use numpy-arrays when working with arrays
a=np.random.rand(500_000,3)
b=np.random.rand(500_000,3)
%timeit res=your_func(a,b)
5.65 s ± 45.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit res=angle(a,b) #without using Numba
3.15 s ± 13 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit res=angle(a,b) #with Numba
2.13 ms ± 441 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
麻木的方法
这项任务很容易实现。
唯一的问题是Python循环非常慢。这可以通过使用Numba或Cython来避免
示例
import numba as nb
import numpy as np
#You can disable parallelization with parallel=False
@nb.njit(fastmath=True,error_model="numpy",parallel=True)
def angle(v1,v2):
#Check the dimensions, this may also have an effect on SIMD-vectorization
assert v1.shape[1]==3
assert v2.shape[1]==3
res=np.empty(v1.shape[0])
for i in nb.prange(v1.shape[0]):
dot=0.
a=0.
b=0.
for j in range(3):
dot+=v1[i,j]*v2[i,j]
a+=v1[i,j]**2
b+=v2[i,j]**2
res[i]=np.arccos(dot/(np.sqrt(a*b)))
return res
计时
#Use numpy-arrays when working with arrays
a=np.random.rand(500_000,3)
b=np.random.rand(500_000,3)
%timeit res=your_func(a,b)
5.65 s ± 45.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit res=angle(a,b) #without using Numba
3.15 s ± 13 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit res=angle(a,b) #with Numba
2.13 ms ± 441 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
问题是:你真的需要这个角度吗?对于许多3d(和2d)计算,通常可以跳过角度(arccos)并比较点积本身。Arccos是这里性能最差的一个,点积是由简单的计算组成的。如果你足够绝望,你可以创建一个Arccos查找表,比如说有数千个条目。然后可以将参数缩放并截断为整数,即表中的索引。查找速度很快。你的精度会受到限制,但你可以估计误差,看看你是否能接受。当我预先计算单位向量时,我能做点积而不在a和b上循环吗?问题是:你真的需要角度吗?对于许多3d(和2d)计算,通常可以跳过角度(arccos)并比较点积本身。Arccos是这里性能最差的一个,点积是由简单的计算组成的。如果你足够绝望,你可以创建一个Arccos查找表,比如说有数千个条目。然后可以将参数缩放并截断为整数,即表中的索引。查找速度很快。你的精度是有限的,但你可以估计误差,看看你是否能接受。当我预先计算单位向量时,我能做点积而不在a和b上循环吗?