una tamaño suma multiplicar multiplicacion matriz matrices inversa ejercicios python numpy numpy-broadcasting

tamaño - suma y multiplicacion de matrices en python



NumPy Broadcasting: cálculo de la suma de las diferencias al cuadrado entre dos matrices (3)

tengo el siguiente código. Está tomando una eternidad en Python. Debe haber una manera de traducir este cálculo en una transmisión ...

def euclidean_square(a,b): squares = np.zeros((a.shape[0],b.shape[0])) for i in range(squares.shape[0]): for j in range(squares.shape[1]): diff = a[i,:] - b[j,:] sqr = diff**2.0 squares[i,j] = np.sum(sqr) return squares


Otra solución además de usar cdist es la siguiente

difference_squared = np.zeros((a.shape[0], b.shape[0])) for dimension_iterator in range(a.shape[1]): difference_squared = difference_squared + np.subtract.outer(a[:, dimension_iterator], b[:, dimension_iterator])**2.


Puede usar np.einsum después de calcular las diferencias de forma broadcasted way , de esta manera:

ab = a[:,None,:] - b out = np.einsum(''ijk,ijk->ij'',ab,ab)

O use scipy''s cdist con su argumento métrico opcional establecido como ''sqeuclidean'' para darnos las distancias cuadradas euclidianas según sea necesario para nuestro problema, así:

from scipy.spatial.distance import cdist out = cdist(a,b,''sqeuclidean'')


Recolecté los diferentes métodos propuestos aquí, y en other dos questions , y medí la velocidad de los diferentes métodos:

import numpy as np import scipy.spatial import sklearn.metrics def dist_direct(x, y): d = np.expand_dims(x, -2) - y return np.sum(np.square(d), axis=-1) def dist_einsum(x, y): d = np.expand_dims(x, -2) - y return np.einsum(''ijk,ijk->ij'', d, d) def dist_scipy(x, y): return scipy.spatial.distance.cdist(x, y, "sqeuclidean") def dist_sklearn(x, y): return sklearn.metrics.pairwise.pairwise_distances(x, y, "sqeuclidean") def dist_layers(x, y): res = np.zeros((x.shape[0], y.shape[0])) for i in range(x.shape[1]): res += np.subtract.outer(x[:, i], y[:, i])**2 return res # inspired by the excellent https://github.com/droyed/eucl_dist def dist_ext1(x, y): nx, p = x.shape x_ext = np.empty((nx, 3*p)) x_ext[:, :p] = 1 x_ext[:, p:2*p] = x x_ext[:, 2*p:] = np.square(x) ny = y.shape[0] y_ext = np.empty((3*p, ny)) y_ext[:p] = np.square(y).T y_ext[p:2*p] = -2*y.T y_ext[2*p:] = 1 return x_ext.dot(y_ext) # https://.com/a/47877630/648741 def dist_ext2(x, y): return np.einsum(''ij,ij->i'', x, x)[:,None] + np.einsum(''ij,ij->i'', y, y) - 2 * x.dot(y.T)

Utilizo timeit para comparar la velocidad de los diferentes métodos. Para la comparación, uso vectores de longitud 10, con 100 vectores en el primer grupo y 1000 vectores en el segundo grupo.

import timeit p = 10 x = np.random.standard_normal((100, p)) y = np.random.standard_normal((1000, p)) for method in dir(): if not method.startswith("dist_"): continue t = timeit.timeit(f"{method}(x, y)", number=1000, globals=globals()) print(f"{method:12} {t:5.2f}ms")

En mi computadora portátil, los resultados son los siguientes:

dist_direct 5.07ms dist_einsum 3.43ms dist_ext1 0.20ms <-- fastest dist_ext2 0.35ms dist_layers 2.82ms dist_scipy 0.60ms dist_sklearn 0.67ms

Si bien los dos métodos dist_ext1 y dist_ext2 , ambos basados ​​en la idea de escribir (xy)**2 como x**2 - 2*x*y + y**2 , son muy rápidos, hay una desventaja: cuando la distancia entre x e y es muy pequeño, debido a un error de cancelación, el resultado numérico a veces puede ser (muy levemente) negativo.