equivalente pdist2 en MATLAB versión 7

Necesito calcular la distancia euclidiana entre 2 matrices en matlab. Actualmente estoy usando bsxfun y calculando la distancia como a continuación (adjunto un fragmento del código):

for i=1:4754 test_data=fea_test(i,:); d=sqrt(sum(bsxfun(@minus, test_data, fea_train).^2, 2)); end 

El tamaño de fea_test es 4754×1024 y fea_train es 6800×1024, usando su bucle for está haciendo que la ejecución del for tome aproximadamente 12 minutos, lo que creo que es demasiado alto. ¿Hay alguna forma de calcular la distancia euclidiana entre ambas matrices más rápido?

Me dijeron que eliminando bucles innecesarios puedo reducir el tiempo de ejecución. También sé que pdist2 puede ayudar a reducir el tiempo de cálculo, pero como uso la versión 7. de matlab, no tengo la función pdist2. La actualización no es una opción.

Alguna ayuda.

Saludos,

Bhavya

Puede vectorizar completamente el cálculo repitiendo las filas de fea_test 6800 veces, y de fea_train 4754 veces, así:

 rA = size(fea_test,1); rB = size(fea_train,1); [I,J]=ndgrid(1:rA,1:rB); d = zeros(rA,rB); d(:) = sqrt(sum(fea_test(J(:),:)-fea_train(I(:),:)).^2,2)); 

Sin embargo, esto daría lugar a matrices intermedias de tamaño 6800x4754x1024 (* 8 bytes para dobles), que ocupará ~ 250 GB de RAM. Por lo tanto, la vectorización completa no funcionará.

Sin embargo, puede reducir el tiempo del cálculo de la distancia por preasignación y al no calcular la raíz cuadrada antes de que sea necesario:

 rA = size(fea_test,1); rB = size(fea_train,1); d = zeros(rA,rB); for i = 1:rA test_data=fea_test(i,:); d(i,:)=sum( (test_data(ones(nB,1),:) - fea_train).^2, 2))'; end d = sqrt(d); 

Aquí hay una implementación vectorizada para calcular la distancia euclidiana que es mucho más rápida que la que tiene (incluso significativamente más rápido que PDIST2 en mi máquina):

 D = sqrt( bsxfun(@plus,sum(A.^2,2),sum(B.^2,2)') - 2*(A*B') ); 

Se basa en el hecho de que: ||uv||^2 = ||u||^2 + ||v||^2 - 2*uv


Considere a continuación una comparación cruda entre los dos métodos:

 A = rand(4754,1024); B = rand(6800,1024); tic D = pdist2(A,B,'euclidean'); toc tic DD = sqrt( bsxfun(@plus,sum(A.^2,2),sum(B.^2,2)') - 2*(A*B') ); toc 

En mi computadora portátil WinXP que ejecuta R2011b, podemos ver una mejora de 10 veces en el tiempo:

 Elapsed time is 70.939146 seconds. %# PDIST2 Elapsed time is 7.879438 seconds. %# vectorized solution 

Debe tener en cuenta que no proporciona exactamente los mismos resultados que PDIST2 hasta la precisión más pequeña. Al comparar los resultados, verá pequeñas diferencias (generalmente cerca de eps la precisión relativa de punto flotante):

 >> max( abs(D(:)-DD(:)) ) ans = 1.0658e-013 

En una nota al margen, he recostackdo alrededor de 10 implementaciones diferentes (algunas son solo pequeñas variaciones una de la otra) para este cálculo de distancia, y las he estado comparando. Te sorprendería lo rápido que pueden ser los bucles simples (gracias al JIT), en comparación con otras soluciones vectorizadas …

Prueba esta versión vectorizada, debería ser bastante eficiente. Editar: acabo de notar que mi respuesta es similar a la de @ Amro.

 function K = calculateEuclideanDist(P,Q) % Vectorized method to compute pairwise Euclidean distance % Returns K(i,j) = sqrt((P(i,:) - Q(j,:))'*(P(i,:) - Q(j,:))) [nP, d] = size(P); [nQ, d] = size(Q); pmag = sum(P .* P, 2); qmag = sum(Q .* Q, 2); K = sqrt(ones(nP,1)*qmag' + pmag*ones(1,nQ) - 2*P*Q'); end