La forma más rápida de encontrar todos los pares únicos de vectores 3D (casi) paralelos de N vectores en Numpy.
Tengo una gran matriz de N = 10000
vectores 3D. Para simplificar, usaré una matriz de 10 x 3 como ejemplo:
import numpy as np
A = np.array([[1.2, 2.3, 0.8],
[3.2, 2.1, 0.5],
[0.8, 4.4, 4.4],
[-0.2, -1.1, -1.1],
[2.4, 4.6, 1.6],
[0.5, 0.96, 0.33],
[1.1, 2.2, 3.3],
[-2.2, -4.41, -6.62],
[3.4, 5.5, 3.8],
[-5.1, -28., -28.1]])
Quiero encontrar todos los pares únicos de vectores que son casi paralelos entre sí. Se debe utilizar una medida de tolerancia, y quiero obtener todos los pares únicos de índices de fila (independientemente del orden). Logré escribir el siguiente código:
def all<em>parallel</em>pairs(A, tol=0.1):
res = set()
for i, v1 in enumerate(A):
for j, v2 in enumerate(A):
if i == j:
continue
norm = np.linalg.norm(np.cross(v1, v2))
if np.isclose(norm, 0., rtol=0, atol=tol):
res.add(tuple(sorted([i, j])))
return np.array(list(res))
print(all<em>parallel</em>pairs(A, tol=0.1))
<p>out[1]: [[0 4]
[2 3]
[6 7]
[4 5]
[0 5]]
Sin embargo, debido a que estoy utilizando dos bucles for, se vuelve lento cuando N
es grande. Siento que debería haber maneras más eficientes y de numpy para hacer esto. ¿Algún consejo?
davy.ai
Una forma de optimizar este código es usar la difusión de numpy en lugar de los dos bucles for. Aquí está el código modificado:
A[:, None]
yA
se difunden para formar una matrizN x N x 3
.np.cross()
calcula el producto cruzado de todos los pares de vectores.np.linalg.norm()
calcula la norma de cada vector de producto cruzado.np.isclose()
crea una máscara booleana para todos los vectores que son casi paralelos.np.argwhere()
encuentra los índices de los elementos True en la máscara.res.update()
agrega todos los pares de índices únicos al conjunto.Este enfoque es mucho más rápido que el enfoque original cuando
N
es grande.