Necesito determinar el ángulo (ángulos) entre dos vectores n-dimensionales en Python. Por ejemplo, la entrada puede ser de dos listas como las siguientes: [1,2,3,4]
y [6,7,8,9]
.Ángulos entre dos vectores n-dimensionales en Python
Respuesta
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)))
Nota: esto va a fallar cuando los vectores tienen la misma o la dirección opuesta. La aplicación correcta está aquí: https://stackoverflow.com/a/13849249/71522
Usando numpy (muy recomendable), que haría:
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
La última línea puede resultar en un error que he encontrado fuera debido a errores de redondeo. Por lo tanto, si puntea (u, u)/norma (u) ** 2 resulta en 1.0000000002 y luego falla el arco (también 'funciona' para vectores antiparalelos) – BandGap
He probado con u = [1,1,1 ] u = [1,1,1,1] funciona bien pero cada dimensión añadida devuelve valores ligeramente más pequeños o más pequeños que 1 ... – BandGap
Nota: ** esto fallará ** (rendimiento 'nan') cuando la dirección de los dos vectores es idéntico o opuesto. Vea mi respuesta para una versión más correcta. –
Nota: todas las otras respuestas aquí se producirá un error si los dos vectores tienen ya sea la misma dirección (por ejemplo, (1, 0, 0)
, (1, 0, 0)
) o direcciones opuestas (ex, (-1, 0, 0)
, (1, 0, 0)
).
Aquí es una función que manejar correctamente estos casos:
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))
¿No sería mejor usar 'np.isnan' en lugar de uno de la biblioteca matemática? En teoría, deberían ser idénticos, pero no estoy seguro en la práctica. De cualquier manera, me imagino que sería más seguro. – Hooked
La única diferencia es que 'np.isnan' hará algo sensato si la entrada es una matriz, que nunca será el caso aquí. Sin embargo, usar 'np.isnan' definitivamente sería más limpio (no estoy seguro de por qué usé' math.isnan' ...), así que lo cambiaré. –
También puede usar 'angle = np.arccos (np.clip (np.dot (v1_u, v2_u), - 1,1))' y omitir el negocio if-else. – letmaik
Usando numpy y el cuidado de los errores de redondeo de banda prohibida:
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)
Nota, esta función será una excepción si uno de los vectores tienen una magnitud cero (se dividen por 0).
La otra posibilidad es usar simplemente numpy
y le da el ángulo interior
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)
y aquí está la salida:
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
- 1. ¿La diferencia más pequeña entre dos ángulos?
- 2. ¿Ángulo entre dos vectores 2d, diferencia entre dos métodos?
- 3. Cálculo si un ángulo está entre dos ángulos
- 4. Obteniendo quaternion para rotar entre dos vectores
- 5. Promedio de dos ángulos con envoltura alrededor
- 6. Producto en cruz de dos vectores en Python
- 7. C++: Comparando dos vectores
- 8. La diferencia más pequeña entre 2 ángulos
- 9. "mover" dos vectores juntos
- 10. Comparar dos vectores C++
- 11. Calcular la distancia entre dos vectores de diferente longitud
- 12. vectores propios Python: diferencias entre numpy.linalg, scipy.linalg y scipy.sparse.linalg
- 13. Diferencias entre vectores _including_ NA
- 14. "Bloqueando" dos vectores y ordenándolos
- 15. Comparando dos vectores en una declaración if
- 16. Diferencia entre dos fechas en Python
- 17. Días entre dos fechas en Python
- 18. Crear conexión entre dos computadoras en python
- 19. Calculando la distancia de Hamming para dos vectores en R?
- 20. Alternar, entrelazar o entrelazar dos vectores
- 21. Salida de tubería Python entre dos subprocesos
- 22. Comprueba si dos vectores son iguales
- 23. ¿Cómo calculo la similitud del coseno de dos vectores?
- 24. Encontrar el ángulo firmado entre los vectores
- 25. Interweaving vectores
- 26. ¿Cómo obtengo caracteres comunes a dos vectores en C++?
- 27. ¿Puede una función en R devolver dos vectores?
- 28. ¿Cómo combino dos vectores de diferente longitud en I
- 29. Calcular el producto escalar de dos vectores en C++
- 30. Rellene la matriz numpy de la diferencia de dos vectores
Además, si solo necesita cos, sin, tan de ángulo, y no el ángulo en sí mismo, entonces puede omitir math.acos para obtener coseno, y usar producto cruzado para obtener seno. – mbeckish
Esto es exactamente lo que estaba buscando, ¡gracias! – Peter
Dado que 'math.sqrt (x)' es equivalente a 'x ** 0.5' y' math.pow (x, y) 'es equivalente a' x ** y', me sorprende que hayan sobrevivido al hacha de redundancia manejado durante la transición de Python 2.x-> 3.0. En la práctica, usualmente hago este tipo de cosas numéricas como parte de un proceso de cómputo más intensivo, y el soporte del intérprete para '**' ir directamente al bytecode BINARY_POWER, frente a la búsqueda de 'matemática', el acceso a su atributo 'sqrt', y luego el código de byte dolorosamente lento CALL_FUNCTION, puede hacer una mejora mensurable en la velocidad sin costo de codificación o legibilidad. – PaulMcG