Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
710 views
in Technique[技术] by (71.8m points)

arrays - Find the distance from one point in a matrix to all other points in a matrix

I have a matrix a and I want to calculate the distance from one point to all other points. So really the outcome matrix should have a zero (at the point I have chosen) and should appear as some sort of circle of numbers around that specific point.

This is what I have already but I cant seem to get the correct outcome.

a = [1 2 3 4 5 6 7 8 9 10]

for i = 2:20
    a(i,:) = a(i-1,:) + 1;
end

N = 10

for I = 1:N
    for J = 1:N
        dx = a(I,1)-a(J,1);
        dy = a(I,2)-a(J,2);
        distance(I,J) = sqrt(dx^2 + dy^2)
    end
end
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your a matrix is a 1D vector and is incompatible with the nested loop, which computes distance in 2D space from each point to each other point. So the following answer applies to the problem of finding all pairwise distances in a N-by-D matrix, as your loop does for the case of D=2.

Option 1 - pdist

I think you are looking for pdist with the 'euclidean' distance option.

a = randn(10, 2); %// 2D, 10 samples
D = pdist(a,'euclidean');  %// euclidean distance

Follow that by squareform to get the square matrix with zero on the diagonal as you want it:

distances = squareform(D);

Option 2 - bsxfun

If you don't have pdist, which is in the Statistics Toolbox, you can do this easily with bsxfun:

da = bsxfun(@minus,a,permute(a,[3 2 1]));
distances = squeeze(sqrt(sum(da.^2,2)));

Option 3 - reformulated equation

You can also use an alternate form of Euclidean (2-norm) distance,

||A-B|| = sqrt ( ||A||^2 + ||B||^2 - 2*A.B )

Writing this in MATLAB for two data arrays u and v of size NxD,

dot(u-v,u-v,2) == dot(u,u,2) + dot(v,v,2) - 2*dot(u,v,2) % useful identity
%// there are actually small differences from floating point precision, but...
abs(dot(u-v,u-v,2) - (dot(u,u,2) + dot(v,v,2) - 2*dot(u,v,2))) < 1e-15

With the reformulated equation, the solution becomes:

aa = a*a';
a2 = sum(a.*a,2); % diag(aa)
a2 = bsxfun(@plus,a2,a2');
distances = sqrt(a2 - 2*aa);

You might use this method if Option 2 eats up too much memory.

Timings

For a random data matrix of size 1e3-by-3 (N-by-D), here are timings for 100 runs (Core 2 Quad, 4GB DDR2, R2013a).

  • Option 1 (pdist): 1.561150 sec (0.560947 sec in pdist)
  • Option 2 (bsxfun): 2.695059 sec
  • Option 3 (bsxfun alt): 1.334880 sec

Findings: (i) Do computations with bsxfun, use the alternate formula. (ii) the pdist+squareform option has comparable performance. (iii) The reason why squareform takes twice as much time as pdist is probably because pdist only computes the triangular matrix since the distance matrix is symmetric. If you can do without the square matrix, then you can avoid squareform and do your computations in about 40% of the time required to do it manually with bsxfun (0.5609/1.3348).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...