मुझे पायथन में दो एन-डायमेंशनल वैक्टर के बीच कोण (एस) निर्धारित करने की आवश्यकता है। उदाहरण के लिए, इनपुट निम्न की तरह दो सूचियां हो सकती हैं: [1,2,3,4]
और [6,7,8,9]
।
मुझे पायथन में दो एन-डायमेंशनल वैक्टर के बीच कोण (एस) निर्धारित करने की आवश्यकता है। उदाहरण के लिए, इनपुट निम्न की तरह दो सूचियां हो सकती हैं: [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
math.sqrt(x)
के बराबर है x**0.5
और math.pow(x,y)
इसके बराबर है x**y
, मुझे आश्चर्य है कि पायथन 2.x-> 3.0 संक्रमण के दौरान इन अतिरेक कुल्हाड़ियों से बच गए। व्यवहार में, मैं आमतौर पर इस प्रकार की संख्यात्मक चीजों को एक बड़ी कम्प्यूट-गहन प्रक्रिया के हिस्से के रूप में कर रहा हूं, और '**' के लिए दुभाषिया का समर्थन सीधे बायटेकोड BINARY_POWER के लिए जा रहा है, बनाम 'गणित' की खोज, पहुंच इसकी विशेषता 'sqrt', और फिर दर्द से धीमी गति से bytecode CALL_FUNCTION, बिना किसी कोडिंग या पठनीयता के गति में एक औसत दर्जे का सुधार कर सकता है।
angle((1., 1., 1.), (1., 1., 1.))
) हैं। थोड़ा और सही संस्करण के लिए मेरा जवाब देखें।
नोट : यहां अन्य सभी उत्तर विफल हो जाएंगे यदि दोनों वैक्टर में एक ही दिशा (पूर्व (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))
np.isnan
गणित की लाइब्रेरी से एक के बजाय इसका उपयोग करना बेहतर नहीं होगा ? सिद्धांत रूप में वे समान होना चाहिए, लेकिन मैं अभ्यास में निश्चित नहीं हूं। किसी भी तरह से मुझे लगता है कि यह सुरक्षित होगा।
arccos
सीधे और सुरक्षित रूप से उपयोग कर सकता है । : [140] में: np.arccos (np.dot (np.array ([1,0,0]), np.array ([- 1,0,0])) आउट [140]: 3.1415926535898931 In [ 141]: np.arccos (np.dot (np.array ([1,0,0]), np.array ([1,0,0])) आउट [141]: 0.0
unit_vector
। एक संभावना यह है कि इस फ़ंक्शन में इनपुट वेक्टर को वापस कर दिया जाए जब यह मामला हो।
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
nan
) जब दो वैक्टर की दिशा समान या विपरीत होती है। अधिक सही संस्करण के लिए मेरा उत्तर देखें।
angle = arccos(clip(c, -1, 1))
गोल मुद्दों से बचना चाहिए । यह @DavidWolever का मुद्दा हल करता है।
clip
संख्यात्मक आयातों की सूची में जोड़ा जाना चाहिए।
दूसरी संभावना बस उपयोग कर रही है 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 वैक्टर के साथ काम कर रहे हैं, तो आप टूलबेल्ट वीजी का उपयोग करके इसे संक्षिप्त रूप से कर सकते हैं । यह सुन्न के ऊपर एक हल्की परत है।
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 में वर्बोज़ या अपारदर्शी हैं।
डेविड वोलेवर का समाधान अच्छा है, लेकिन
यदि आप हस्ताक्षरित कोण चाहते हैं तो आपको यह निर्धारित करना होगा कि क्या दी गई जोड़ी सही है या बाएं हाथ की है ( आगे की जानकारी के लिए विकि देखें )।
इसके लिए मेरा समाधान है:
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))
यह इस वजह से सही नहीं है, NotImplementedError
लेकिन मेरे मामले में यह अच्छी तरह से काम करता है। इस व्यवहार को ठीक किया जा सकता है (क्योंकि किसी भी जोड़ी के लिए हाथ का निर्धारण किया जाता है) लेकिन यह अधिक कोड लेता है जो मुझे चाहिए और लिखना होगा।
दो वैक्टर (एन-डायमेंशनल वेक्टर के लिए काम करता है) के बीच कोण खोजने का आसान तरीका,
पायथन कोड:
import numpy as np
vector1 = [1,0,0]
vector2 = [0,1,0]
unit_vector1 = vector1 / np.linalg.norm(vector1)
unit_vector2 = vector2 / np.linalg.norm(vector2)
dot_product = np.dot(unit_vector1, unit_vector2)
angle = np.arccos(dot_product) #angle in radian
Sgt काली मिर्च के शानदार उत्तर पर निर्माण करना और संरेखित वैक्टर के लिए समर्थन जोड़ना और Numba का उपयोग करके 2x से अधिक स्पीडअप जोड़ना
@njit(cache=True, nogil=True)
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:
sign = 1
else:
sign = -np.sign(minor)
dot_p = np.dot(v1_u, v2_u)
dot_p = min(max(dot_p, -1.0), 1.0)
return sign * np.arccos(dot_p)
@njit(cache=True, nogil=True)
def unit_vector(vector):
""" Returns the unit vector of the vector. """
return vector / np.linalg.norm(vector)
def test_angle():
def npf(x):
return np.array(x, dtype=float)
assert np.isclose(angle(npf((1, 1)), npf((1, 0))), pi / 4)
assert np.isclose(angle(npf((1, 0)), npf((1, 1))), -pi / 4)
assert np.isclose(angle(npf((0, 1)), npf((1, 0))), pi / 2)
assert np.isclose(angle(npf((1, 0)), npf((0, 1))), -pi / 2)
assert np.isclose(angle(npf((1, 0)), npf((1, 0))), 0)
assert np.isclose(angle(npf((1, 0)), npf((-1, 0))), pi)
%%timeit
परिणाम बिना नंबा
और साथ
सुन्न का उपयोग करना और 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)
ध्यान दें, यह फ़ंक्शन एक अपवाद को फेंक देगा यदि वैक्टर में से एक में शून्य परिमाण है (0 से विभाजित करें)।
जो कुछ (एसईओ जटिलताओं के कारण) हो सकता है, उसके लिए यहां दो लाइनों के बीच के कोण की गणना करने की कोशिश कर रहे हैं , जैसे कि (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