Вычислите угол между рядами двух матриц в numpy - PullRequest
0 голосов
/ 09 июня 2018

У меня есть две матрицы, состоящие из трехмерных векторов (числовой массив 1D), и мне нужно вычислить угол между векторами по строкам и вернуть результаты в одномерном массиве.Я знаю, как рассчитать угол между двумя 1d векторами.Как правильно это сделать?

*** Результирующие углы приведены в градусах, а не в радианах.

К настоящему времени у меня есть это:

import numpy as np

A = np.array([[1,0,0],
              [0,1,0],
              [0,0,1]])

B = np.array([[1,0,1],
              [1,1,0],
              [0,1,0]])

def angle(V1,V2):
    """
    angle between vectors V1 and V2 in degrees using
    angle = arccos ( V1 dot V2 / norm(V1) * norm(V2) ) *180/np.pi
    """

    cos_of_angle = V1.dot(V2) / (np.linalg.norm(V1) * np.linalg.norm(V2)) 
    return np.arccos(np.clip(cos_of_angle,-1,1))  * 180/np.pi

Обратите внимание на масштабирующий член 180 / np.pi для преобразования из рад в град.

Я хотел бы иметь массив:

C = [ angle(A[0],B[0]) , angle(A[1],B[1])...... and so on]

Очень признателен, если кто-то может помочь.

Ответы [ 2 ]

0 голосов
/ 04 апреля 2019

Если вы работаете с трехмерными векторами, вы можете сделать это кратко, используя пояс для инструментов vg .Это легкий слой поверх numpy, и он одинаково хорошо работает с отдельными векторами и стеками векторов.

import numpy as np
import vg

A = np.array([[1,0,0],
              [0,1,0],
              [0,0,1]])

B = np.array([[1,0,1],
              [1,1,0],
              [0,1,0]])

vg.angle(A, B)

Я создал библиотеку при моем последнем запуске, где она была мотивирована такими действиями: простые идеиподробные или непрозрачные в NumPy.

0 голосов
/ 09 июня 2018

Мы могли бы использовать einsum для замены вычислений точечных произведений и axis параметров для norm, чтобы иметь векторизованное решение, например: *

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))

Мы могли бы продолжить оптимизацию и получить больше einsum, особенно для вычисления norms с ним.Следовательно, мы можем использовать его следующим образом -

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))

Следовательно, чтобы решить наш случай, чтобы получить выходные данные в градусах -

out = angle_rowwise(A, B)*180/np.pi
...