Octave: calcola la distanza tra due matrici di vettori


12

Supponiamo che io abbia due matrici Nx2, Mx2 che rappresentano rispettivamente i vettori N, M 2d. Esiste un modo semplice e buono per calcolare le distanze tra ciascuna coppia di vettori (n, m)?

Il modo semplice ma inefficiente è ovviamente:

d = zeros(N, M);
for i = 1:N,
  for j = 1:M,
    d(i,j) = norm(n(i,:) - m(j,:));
  endfor;
endfor;

La risposta più vicina che ho trovato è bsxfun, usata così:

bsxfun(inline("x-y"),[1,2,3,4],[3;4;5;6])

ans =
  -2 -1  0  1
  -3 -2 -1  0
  -4 -3 -2 -1
  -5 -4 -3 -2

Ho dato un'occhiata a questo e non ho potuto fare molto meglio di vettorializzare il calcolo. Penso che questo calcolo sia un buon candidato per scrivere una funzione C / Fortran esterna.
Aron Ahmadia,

1
Scommetto che potresti creare una matrice 2xNxM che popoli con un prodotto esterno, quindi quadrare ciascuna delle voci e sommare lungo l'asse zeroth e la radice quadrata. In Python sarebbe simile a: distance_matrix = (n [:,:, nexaxis] * m [:, newaxis ,:]); distance_matrix = distance_matrix ** 2; distance_matrix = sqrt (distance_matrix.sum (axis = 1)); Se hai solo bisogno di conoscere i n-vettori più vicini, ci sono modi molto migliori per farlo!
meawoppl,

3
@meawoppl (New to Octave) Ho scoperto come usare il pacchetto linear-algebra in Octave, che fornisce cartprod, quindi ora posso scrivere: (1) x = cartprod(n(:,1), m(:,1)); (2) y = cartprod(n(:,2), m(:,2)); (3) d = sqrt((x(:,1)-x(:,2)).^2+(y(:,1)-y(:,2)).^2) .. che corre molto più veloce!
Kelley van Evert,

Risposte:


6

La vettorializzazione è semplice in queste situazioni usando una strategia come questa:

eN = ones(N,1);
eM = ones(M,1);
d  = sqrt(eM*n.^2' - 2*m*n' + m.^2*eN');

Ecco un esempio che vettorializza il ciclo for con uno speedup 15x per M = 1000 e N = 2000.

n = rand(N,2);
m = rand(M,2);
eN = ones(N,2);
eM = ones(2,M);

tic;
d_vect  = sqrt(eN*m.^2' - 2*n*m' + n.^2*eM);
vect_time = toc;

tic;
for i=1:N
  for j=1:M
     d_for(i,j) = norm(n(i,:)-m(j,:));
  end
end
for_time = toc; 

assert(norm(d_vect-d_for) < 1e-10*norm(d_for)) 

David, piacere di vederti su Scicomp! Ho spudoratamente modificato il tuo frammento di codice e l'ho ampliato un po ', per favore ripristina se le mie modifiche sono andate nella direzione sbagliata dal chiarire cosa volevi.
Aron Ahmadia,

2

Da Octave 3.4.3 e successive l'operatore esegue la trasmissione automatica (usa internamente bsxfun). Quindi puoi procedere in questo modo.

Dx = N(:,1) - M(:,1)';
Dy = N(:,2) - M(:,2)';
D = sqrt (Dx.^2 + Dy.^2);

Puoi fare lo stesso usando una matrice 3d ma immagino che questo sia più chiaro. D è una matrice NxM di distanze, ogni vettore in N contro ogni vettore in M.

Spero che sia di aiuto

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.