파이썬에서 두 개의 n 차원 벡터 사이의 각도
파이썬에서 두 개의 n 차원 벡터 사이의 각도를 결정해야합니다. 예를 들어, 입력은 다음과 같은 두 개의 목록 일 수 있습니다. [1,2,3,4]및 [6,7,8,9].
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)))
참고 : 벡터의 방향이 같거나 반대이면 실패합니다. 올바른 구현은 다음과 같습니다 : https://stackoverflow.com/a/13849249/71522
참고 : 두 벡터 중 하나를 같은 방향 (예, 경우 여기에 다른 답변 모두 실패 (1, 0, 0), (1, 0, 0)) 또는 반대 방향 (예, (-1, 0, 0), (1, 0, 0)).
다음은 이러한 경우를 올바르게 처리하는 함수입니다.
import numpy as np
def unit_vector(vector):
""" Returns the unit vector of the vector. """
return vector / np.linalg.norm(vector)
def angle_between(v1, v2):
""" Returns the angle in radians between vectors 'v1' and 'v2'::
>>> angle_between((1, 0, 0), (0, 1, 0))
1.5707963267948966
>>> angle_between((1, 0, 0), (1, 0, 0))
0.0
>>> angle_between((1, 0, 0), (-1, 0, 0))
3.141592653589793
"""
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))
사용 NumPy와 (추천)을, 당신이 할 것입니다 :
from numpy import (array, dot, arccos, clip)
from numpy.linalg import norm
u = array([1.,2,3,4])
v = ...
c = dot(u,v)/norm(u)/norm(v) # -> cosine of the angle
angle = arccos(clip(c, -1, 1)) # if you really want the angle
다른 가능성은 그냥 사용하는 numpy것이고 그것은 당신에게 내부 각도를 제공합니다
import numpy as np
p0 = [3.5, 6.7]
p1 = [7.9, 8.4]
p2 = [10.8, 4.8]
'''
compute angle (in degrees) for p0p1p2 corner
Inputs:
p0,p1,p2 - points in the form of [x,y]
'''
v0 = np.array(p0) - np.array(p1)
v1 = np.array(p2) - np.array(p1)
angle = np.math.atan2(np.linalg.det([v0,v1]),np.dot(v0,v1))
print np.degrees(angle)
다음은 출력입니다.
In [2]: p0, p1, p2 = [3.5, 6.7], [7.9, 8.4], [10.8, 4.8]
In [3]: v0 = np.array(p0) - np.array(p1)
In [4]: v1 = np.array(p2) - np.array(p1)
In [5]: v0
Out[5]: array([-4.4, -1.7])
In [6]: v1
Out[6]: array([ 2.9, -3.6])
In [7]: angle = np.math.atan2(np.linalg.det([v0,v1]),np.dot(v0,v1))
In [8]: angle
Out[8]: 1.8802197318858924
In [9]: np.degrees(angle)
Out[9]: 107.72865519428085
3D 벡터로 작업하는 경우 toolbelt vg를 사용하여 간결하게 수행 할 수 있습니다 . numpy 위에 밝은 레이어입니다.
import numpy as np
import vg
vec1 = np.array([1, 2, 3])
vec2 = np.array([7, 8, 9])
vg.angle(vec1, vec2)
투영을 통해 각도를 계산하기 위해보기 각도를 지정할 수도 있습니다.
vg.angle(vec1, vec2, look=vg.basis.z)
또는 투영을 통해 부호있는 각도를 계산합니다.
vg.signed_angle(vec1, vec2, look=vg.basis.z)
나는 마지막 스타트 업에서 라이브러리를 만들었는데, NumPy에서 장황하거나 불투명 한 단순한 아이디어와 같은 용도로 동기를 부여 받았습니다.
(SEO의 합병증으로 인해) 기하학적 선 에서와 같이 파이썬에서 두 줄 사이의 각도를 계산하려고 여기에서 끝났을 수있는 소수를 위해 다음 과 같은 최소 솔루션이 있습니다 ( 모듈을 사용 하지만 쉽게 수정할 수 없음).(x0, y0), (x1, y1)shapely
from shapely.geometry import LineString
import numpy as np
ninety_degrees_rad = 90.0 * np.pi / 180.0
def angle_between(line1, line2):
coords_1 = line1.coords
coords_2 = line2.coords
line1_vertical = (coords_1[1][0] - coords_1[0][0]) == 0.0
line2_vertical = (coords_2[1][0] - coords_2[0][0]) == 0.0
# Vertical lines have undefined slope, but we know their angle in rads is = 90° * π/180
if line1_vertical and line2_vertical:
# Perpendicular vertical lines
return 0.0
if line1_vertical or line2_vertical:
# 90° - angle of non-vertical line
non_vertical_line = line2 if line1_vertical else line1
return abs((90.0 * np.pi / 180.0) - np.arctan(slope(non_vertical_line)))
m1 = slope(line1)
m2 = slope(line2)
return np.arctan((m1 - m2)/(1 + m1*m2))
def slope(line):
# Assignments made purely for readability. One could opt to just one-line return them
x0 = line.coords[0][0]
y0 = line.coords[0][1]
x1 = line.coords[1][0]
y1 = line.coords[1][1]
return (y1 - y0) / (x1 - x0)
그리고 사용은
>>> line1 = LineString([(0, 0), (0, 1)]) # vertical
>>> line2 = LineString([(0, 0), (1, 0)]) # horizontal
>>> angle_between(line1, line2)
1.5707963267948966
>>> np.degrees(angle_between(line1, line2))
90.0
numpy 사용 및 BandGap의 반올림 오류 처리 :
from numpy.linalg import norm
from numpy import dot
import math
def angle_between(a,b):
arccosInput = dot(a,b)/norm(a)/norm(b)
arccosInput = 1.0 if arccosInput > 1.0 else arccosInput
arccosInput = -1.0 if arccosInput < -1.0 else arccosInput
return math.acos(arccosInput)
Note, this function will throw an exception if one of the vectors has zero magnitude (divide by 0).
David Wolever's solution is good, but
If you want to have signed angles you have to determine if a given pair is right or left handed (see wiki for further info).
My solution for this is:
def unit_vector(vector):
""" Returns the unit vector of the vector"""
return vector / np.linalg.norm(vector)
def angle(vector1, vector2):
""" Returns the angle in radians between given vectors"""
v1_u = unit_vector(vector1)
v2_u = unit_vector(vector2)
minor = np.linalg.det(
np.stack((v1_u[-2:], v2_u[-2:]))
)
if minor == 0:
raise NotImplementedError('Too odd vectors =(')
return np.sign(minor) * np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0))
It's not perfect because of this NotImplementedError but for my case it works well. This behaviour could be fixed (cause handness is determined for any given pair) but it takes more code that I want and have to write.
참고URL : https://stackoverflow.com/questions/2827393/angles-between-two-n-dimensional-vectors-in-python
'Program Club' 카테고리의 다른 글
| CamelCase 단어를 PHP preg_match (정규식)를 사용하여 단어로 분할 (0) | 2020.11.25 |
|---|---|
| ios facebook sdk 4.0 로그인 오류 코드 304 (0) | 2020.11.25 |
| 신속하게 문자열에서 숫자가 아닌 모든 문자를 제거하십시오. (0) | 2020.11.25 |
| Java에서 문자열의 문자를 어떻게 바꾸나요? (0) | 2020.11.25 |
| 투표 경쟁에서 사기꾼 사냥 (0) | 2020.11.24 |