How to create for loop for calculating euclidean distance of a matrix?

18 views (last 30 days)
Hi!
I am having some trouble figuring out how to structure this for loop.. I have an array called 'Coordinates' that contains a varying number of rows, and constant number of columns. col 1 = x, col 2 = y, col 3 = z. The number of rows varies based on how many events occur in a single observation, but columns are consistent throughout.
Coordinates =
-.6 .5 -4.1
-.9 .4 -4.1
-1.1 .2 -4.2
I need to write a for loop that calculates the euclidean distance between each of these xyz coordinates and store it in a new array called 'Distances'.
icoordinates = nobservations - 1; %creates a variable that consists of number of observations -1
config.Calculated.Distances = []; % create empty vector to store distances
for i_coord = 1:icoordinates %for each observation
curdistance = config.Calculated.Coordinates(:, :, i_coord);
curdistance = sqrt(sum((Coordinates(i+1,:) - Coordinates(i,:)).^2));
config.Calculated.Distances = [config.Calculated.Distances curdistance];
end
close all;
When I run the code as above ^ I get the following error and my Distances array remains empty
1 icoordinates = nobservations - 1; % creates a variable that consists of number of scan patterns -1
Index in position 1 is invalid. Array indices must be positive integers or logical values.
Error in distancecalc (line 7)
curdistance = sqrt(sum((Coordinates(i+1,:) - Coordinates(i,:)).^2));
Any help with figuring out how to structure this for loop would be greatly appreciated, I'm a MATLAB novice and would love to learn!
Thanks,
Jade

Accepted Answer

Voss
Voss on 3 Apr 2024
Something like what follows might be what you're trying to do (I'm assuming config.Calculated.Coordinates is the same as Coordinates). This calculates the distance between each consecutive pair of points (i.e., each pair of adjacent rows in the Coordinates matrix):
Coordinates = [
-0.6 0.5 -4.1
-0.9 0.4 -4.1
-1.1 0.2 -4.2
];
nobservations = size(Coordinates,1);
icoordinates = nobservations - 1; %creates a variable that consists of number of observations -1
Distances = []; % create empty vector to store distances
for i_coord = 1:icoordinates %for each observation
curdistance = sqrt(sum((Coordinates(i_coord+1,:) - Coordinates(i_coord,:)).^2));
Distances = [Distances curdistance];
end
Distances
Distances = 1x2
0.3162 0.3000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
However, rather than growing your Distances vector one element at a time, it is a good idea to pre-allocate it (especially if the number of observations is large), since appending one element at a time to a vector is inefficient. To Pre-allocate an array is to initialize it to the correct size with zeros (or whatever value makes sense in context) before calculating its elements' values in a loop.
Distances = zeros(1,icoordinates); % pre-allocated row vector of Distances
for i_coord = 1:icoordinates %for each observation
curdistance = sqrt(sum((Coordinates(i_coord+1,:) - Coordinates(i_coord,:)).^2));
Distances(i_coord) = curdistance; % assign the i_coord element of Distances
end
Distances
Distances = 1x2
0.3162 0.3000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Now, as with many things in MATLAB, there are useful functions for doing this without a loop. In this case you can use the diff function to take the differences between adjacent rows of Coordinates, which produces an icoordinates-by-3 matrix, and also specify in the sum function that the sum is to be done over the second dimension - that is, to sum the columns of the squared differences (since now all rows are being operated on at once).
Distances = sqrt(sum(diff(Coordinates, 1, 1).^2, 2));
% ^ first difference
% ^ over the first dimension (row-by-row)
% ^ sum across the second dimension (sum the columns)
Distances
Distances = 2x1
0.3162 0.3000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Of course, it could be that you don't mean to be finding the distances only between the coordinates in adjacent rows of Coordinates but between each row and every other row. To do that using your intial approach requires two nested for loops. The second loop starts at i_coord+1 so that you're not calculating the distance between a point and itself and not repeating any pairs (i.e, the distance between point A and point B is the same as the distance between point B and point A - no need to calculate that distance twice):
Distances = []; % create empty vector to store distances
for i_coord = 1:nobservations %for each observation
for j_coord = i_coord+1:nobservations % and each subsequent observation
curdistance = sqrt(sum((Coordinates(j_coord,:) - Coordinates(i_coord,:)).^2));
Distances = [Distances curdistance];
end
end
Distances
Distances = 1x3
0.3162 0.5916 0.3000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
(Notice there's an extra element in Distances now, the distance between point 1 (first row) and point 3 (third row), which was not calculated before.)
That can be done without any loops as well (this calculates every pairwise distance, including A->B and B->A (note the symmetry of the result) and the distance from a point to itself (note the zeros along the diagonal)):
Distances = sqrt(sum((permute(Coordinates,[1 3 2]) - permute(Coordinates,[3 1 2])).^2, 3))
Distances = 3x3
0 0.3162 0.5916 0.3162 0 0.3000 0.5916 0.3000 0
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
  2 Comments
Jade
Jade on 3 Apr 2024
The first solution worked beautifully, thank you so much! Luckily I don't the number of observations is never more than 20 so I'm not too worried about the inefficiency of growing my array one row at a time. :) Nevertheless, I really appreciated how you included multiple strategies to solve this problem, it was very helpful and informative!
I hope you have a great day, you helped me out immensely!

Sign in to comment.

More Answers (1)

James Tursa
James Tursa on 3 Apr 2024

Categories

Find more on Loops and Conditional Statements in Help Center and File Exchange

Products


Release

R2019b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!