Denken in einer NumPy vektorisiert Weise, die elementweise Differenzierung, quadriert und Summieren entlang der letzten Achse und schließlich immer Quadratwurzel durchführen würde. Also, die Straight-Forward-Implementierung wäre -
np.sqrt(((A - B)**2).sum(-1))
Wir konnten die Quadrierung durchführen und mit np.einsum
entlang der letzten Achse in einem Rutsch Summieren und machen es somit effizienter zu gestalten, wie so -
subs = A - B
out = np.sqrt(np.einsum('ijk,ijk->ij',subs,subs))
eine weitere Alternative mit numexpr
module -
import numexpr as ne
np.sqrt(ne.evaluate('sum((A-B)**2,2)'))
Da wir mit einer Länge von 2
entlang der letzten Achse arbeiten, konnten wir nur sli ce diese und füttern Sie es evaluate
Methode. Bitte beachten Sie, dass das Slicen innerhalb der Evaluierungszeichenfolge nicht möglich ist. So würde die modifizierte Implementierung sein -
a0 = A[...,0]
a1 = A[...,1]
b0 = B[...,0]
b1 = B[...,1]
out = ne.evaluate('sqrt((a0-b0)**2 + (a1-b1)**2)')
Runtime Test
Funktionsdefinitionen -
def sqrt_sum_sq_based(A,B):
return np.sqrt(((A - B)**2).sum(-1))
def einsum_based(A,B):
subs = A - B
return np.sqrt(np.einsum('ijk,ijk->ij',subs,subs))
def numexpr_based(A,B):
return np.sqrt(ne.evaluate('sum((A-B)**2,2)'))
def numexpr_based_with_slicing(A,B):
a0 = A[...,0]
a1 = A[...,1]
b0 = B[...,0]
b1 = B[...,1]
return ne.evaluate('sqrt((a0-b0)**2 + (a1-b1)**2)')
Timings -
In [288]: # Setup input arrays
...: dim = 2
...: N = 1000
...: A = np.random.rand(N,N,dim)
...: B = np.random.rand(N,N,dim)
...:
In [289]: %timeit sqrt_sum_sq_based(A,B)
10 loops, best of 3: 40.9 ms per loop
In [290]: %timeit einsum_based(A,B)
10 loops, best of 3: 22.9 ms per loop
In [291]: %timeit numexpr_based(A,B)
10 loops, best of 3: 18.7 ms per loop
In [292]: %timeit numexpr_based_with_slicing(A,B)
100 loops, best of 3: 8.23 ms per loop
In [293]: %timeit np.linalg.norm(A-B, axis=-1) #@dnalow's soln
10 loops, best of 3: 45 ms per loop
Hätten Sie Links oder Ressourcen, die 'np.einsum' im Vergleich zu normaler numpy Effizienz vergleichen? – jadsq
@jadsq Ich denke [dieses] (http://stackoverflow.com/questions/18365073/why-is-numpys-einsum-faster-than-numpys-built-in-functions), wenn wir über einen allgemeinen Fall sprechen . In diesem speziellen Fall machen wir zwei Dinge auf einmal mit'Einsum' und das macht es hier wirklich nützlich. – Divakar
@Divakar, danke! Ich habe heute wieder etwas Neues von dir gelernt. – MaxU