performance matlab matrix distance euclidean-distance

performance - Calcule eficientemente la distancia euclidiana cuadrada por pares en Matlab



matrix distance (1)

La respuesta usualmente dada aquí se basa en bsxfun (cf. ej. [1] ). Mi enfoque propuesto se basa en la multiplicación de matrices y resulta ser mucho más rápido que cualquier algoritmo comparable que pude encontrar:

helpA = zeros(numA,3*d); helpB = zeros(numB,3*d); for idx = 1:d helpA(:,3*idx-2:3*idx) = [ones(numA,1), -2*A(:,idx), A(:,idx).^2 ]; helpB(:,3*idx-2:3*idx) = [B(:,idx).^2 , B(:,idx), ones(numB,1)]; end distMat = helpA * helpB'';

Tenga en cuenta: para la constante d uno puede reemplazar el -loop por implementaciones codificadas, por ejemplo

helpA(:,3*idx-2:3*idx) = [ones(numA,1), -2*A(:,1), A(:,1).^2, ... % d == 2 ones(numA,1), -2*A(:,2), A(:,2).^2 ]; % etc.

Evaluación:

%% create some points d = 2; % dimension numA = 20000; numB = 20000; A = rand(numA,d); B = rand(numB,d); %% pairwise distance matrix % proposed method: tic; helpA = zeros(numA,3*d); helpB = zeros(numB,3*d); for idx = 1:d helpA(:,3*idx-2:3*idx) = [ones(numA,1), -2*A(:,idx), A(:,idx).^2 ]; helpB(:,3*idx-2:3*idx) = [B(:,idx).^2 , B(:,idx), ones(numB,1)]; end distMat = helpA * helpB''; toc; % compare to pdist2: tic; pdist2(A,B).^2; toc; % compare to [1]: tic; bsxfun(@plus,dot(A,A,2),dot(B,B,2)'')-2*(A*B''); toc; % Another method: added 07/2014 % compare to ndgrid method (cf. Dan''s comment) tic; [idxA,idxB] = ndgrid(1:numA,1:numB); distMat = zeros(numA,numB); distMat(:) = sum((A(idxA,:) - B(idxB,:)).^2,2); toc;

Resultado:

Elapsed time is 1.796201 seconds. Elapsed time is 5.653246 seconds. Elapsed time is 3.551636 seconds. Elapsed time is 22.461185 seconds.

Para una evaluación más detallada, la dimensión y el número de puntos de datos siguen la discusión a continuación (@comments). Resulta que diferentes algos deberían ser preferidos en diferentes configuraciones. En situaciones que no sean críticas, simplemente use la versión pdist2 .

Desarrollo adicional: se puede pensar en reemplazar el euclidiano cuadrado por cualquier otra métrica basada en el mismo principio:

help = zeros(numA,numB,d); for idx = 1:d help(:,:,idx) = [ones(numA,1), A(:,idx) ] * ... [B(:,idx)'' ; -ones(1,numB)]; end distMat = sum(ANYFUNCTION(help),3);

Sin embargo, esto es bastante lento. Podría ser útil reemplazar para d menor la help matriz tridimensional por d matrices bidimensionales. Especialmente para d = 1 proporciona un método para calcular la diferencia por pares mediante una simple multiplicación de matrices:

pairDiffs = [ones(numA,1), A ] * [B''; -ones(1,numB)];

¿Tienes más ideas?

Dado dos conjuntos de puntos d dimensional. ¿Cómo puedo calcular de manera más eficiente la matriz de distancia euclidiana cuadrada por pares en Matlab?

Notación: el conjunto uno está dado por una (numA,d) A y el conjunto dos está dado por una (numB,d) B La matriz de distancia resultante debe tener el formato (numA,numB) .

Puntos de ejemplo:

d = 4; % dimension numA = 100; % number of set 1 points numB = 200; % number of set 2 points A = rand(numA,d); % set 1 given as matrix A B = rand(numB,d); % set 2 given as matrix B