Get the non-zero minimum of a column and its index - matlab

I want to find the minimum value of a column of a matrix of non-negative integers, excluding 0. I know the matrix is square and only has zeros on every element of its main diagonal (i.e. a(i,i)=0 for all i).
I have tried this:
[best_cost,index] = min(star_costs([1:i-1,i+1:nbr],i));
Where nbr is the size of my matrix.
However, the index that is returned is the index excluding the zero, not taking into account the ith element. For example, my first column is:
[0 9 11 5 18 13 14]'
so the code returns best_cost=5and index=3 because the 0 element is excluded. However, I would like to get index=4 as anyone would expect.
Of course just adding 1 does not have sense, as it could happen for any column and, except for the case of this first column, the minimum of the column could be above or below the diagonal.

Replace zeros with inf and then use min.
A(1:size(A,1)+1:end) = inf; %If the diagonal is to be excluded
%if all zeros are to be excluded including non-diagonal elements, use this instead:
%A(A==0) = inf; %Use tolerance if you have floating point numbers
[best_cost, index] = min(A);

As suggested in the comment I would try a work around changing the diagonal to the maximum value of the matrix, assuming that only the zeros on the diagonal are to be omitted.
%create random matrix
A = magic(4)
%change diagonal to the maximum
A(logical(eye(size(A)))) = max(A(:));
And now you can apply your search for the minimum

Related

Column-wise average over unequal number of values in matrix

I am looking for an easy way to obtain the column-wise average of a subset of values in a matrix (indexed by a logical matrix), preferably without having to use a loop. The problem that I am experiencing is that because the number of values in each column is different, matlab collapses the values-matrix and its column-wise mean becomes the total mean (of the entire matrix). Is there a specific function or easy workaround for this problem? See below for an example.
%% define value matrix and logical indexing matrix
values=[1 2 3 4; 5 6 7 8; 9 10 11 12];
indices=[1 0 0 1; 0 1 0 1; 1 1 0 0];
indices=indices==1; %convert to logical
%% calculate column-wise average
mean(values(indices),1)
accumarray-based approach
Use the column index as a grouping variable for accumarray:
[~, col] = find(indices);
result = accumarray(col(:), values(indices), [size(values,2) 1], #mean, NaN).';
Note that:
The second line uses (:) to force the first input to be a column vector. This is needed because the first line may produce col as a row or column vector, depending on the size of indices.
NaN is used as fill value. This is specified as the fifth input to accumarray.
The third input to accumarray defines output size. It is necessary to specify it explicitly (as opposed to letting accumarray figure it out) in case the last columns of indices only contain false.
Hacky approach
Multiply and divide element-wise by indices. That will turn unwanted entries into NaN, which can then be ignored by mean using the 'omitnan' option:
result = mean(values.*indices./indices, 1, 'omitnan');
Manual approach
Multiply element-wise by indices, sum each column, and divide element-wise by the sum of each column of indices:
result = sum(values.*indices, 1) ./ sum(indices, 1);

How do I track when multiple objects touch in MATLAB?

I have x,y pixel coordinates of multiple objects that have been tracked from an image (3744x5616). The coordinates are stored in a structure called objects, e.g.
objects(1).centre = [1868 1236]
The objects are each uniquely identified by a numerical code, e.g.
objects(i).code = 33
I want to be able to record each time any two objects come within a radius of 300 pixels each other. What would be the best way to check through if any objects are touching and then record the identity of both objects involved in the interaction, like object 33 interacts with object 34.
Thanks!
Best thing I can think of right now is a brute force approach. Simply check the distances from one object's centre with the rest of the other objects and manually check if the distances are < 300 pixels.
If you want this fast, we should probably do this without any toolboxes. You can intelligently do this with vanilla MATLAB using bsxfun. First, create separate arrays for the X and Y coordinates of each object:
points = reshape([objects.centre], 2, []);
X = points(1,:);
Y = points(2,:);
[objects.centre] accesses the individual coordinates of each centre field in your structure and unpacks them into a comma-separated list. I reshape this array so that it is 2 rows where the first row is the X coordinate and the second row is the Y coordinate. I extract out the rows and place them into separate arrays.
Next, create two difference matrices for each X and Y where the rows denote one unique coordinate and the columns denote another unique coordinate. The values inside this matrix are the differences between the point i at row i and point j at column j:
Xdiff = bsxfun(#minus, X.', X);
Ydiff = bsxfun(#minus, Y.', Y);
bsxfun stands for Binary Singleton EXpansion FUNction. If you're familiar with the repmat function, it essentially replicates matrices and vectors under the hood so that both inputs you're operating on have the same size. In this case, what I'm doing is specifying X or Y as both of the inputs. One is the transposed version of the other. By doing this bsxfun automatically broadcasts each input so that the inputs match in dimension. Specifically, the first input is a column vector of X and so this gets repeated and stacked horizontally for as many times as there are values in X.
Similarly this is done for the Y value. After you do this, you perform an element-wise subtraction for both outputs and you get the component wise subtraction between one point and another point for X and Y where the row gives you the first point, and the column gives you the second point. As a toy example, imagine we had X = [1 2 3]. Doing a bsxfun call using the above code gives:
>> Xdiff = bsxfun(#minus, [1 2 3].', [1 2 3])
Xdiff =
## | 1 2 3
----------------------
1 | 0 -1 -2
2 | 1 0 -1
3 | 2 1 0
There are some additional characters I placed in the output, but these are used solely for illustration and to give you a point of reference. By taking a row value from the ## column and subtracting from a column value from the ## row gives you the desired subtract. For example, the first row second column illustrates 1 - 2 = -1. The second row, third column illustrates 2 - 3 = -1. If you do this for both the X and Y points, you get the component-wise distances for one point against all of the other points in a symmetric matrix.
You'll notice that this is an anti-symmetric matrix where the diagonal is all 0 ... makes sense since the distance of one dimension of one point with respect to itself should be 0. The bottom left triangular portion of the matrix is the opposite sign of the right... because of the order of subtraction. If you subtracted point 1 with point 2, doing the opposite subtraction gives you the opposite sign. However, let's assume that the rows denote the first object and the columns denote the second object, so you'd want to concentrate on the lower half.
Now, compute the distance, and make sure you set either the upper or lower triangular half to NaN because when computing the distance, the sign gets ignored. If you don't ignore this, we'd find duplicate objects that interact, so object 3 and object 1 would be a different interaction than object 1 and object 3. You obviously don't care about the order, so set either the upper or lower triangular half to NaN for the next step. Assuming Euclidean distance:
dists = sqrt(Xdiff.^2 + Ydiff.^2);
dists(tril(ones(numel(objects))==1)) = NaN;
The first line computes the Euclidean distance of all pairs of points and we use tril to extract the lower triangular portion of a matrix that consists of all logical 1. Extracting this matrix, we use this to set the lower half of the matrix to NaN. This allows us to skip entries we're not interested in. Note that I also set the diagonal to 0, because we're not interested in distances of one object to itself.
Now that you're finally here, search for those objects that are < 300 pixels:
[I,J] = find(dists < 300);
I and J are row/column pairs that determine which rows and columns in the matrix have values < 300, so in our case, each pair of I and J in the array gives you the object locations that are close to each other.
To finally figure out the right object codes, you can do:
codes = [[objects(I).code].' [objects(J).code].'];
This uses I and J to access the corresponding codes of those objects that were similar in a comma-separated list and places them side by side into a N x 2 matrix. As such, each row of codes gives you unique pairs of objects that satisfied the distance requirements.
For copying and pasting:
points = reshape([objects.centre], 2, []);
X = points(1,:);
Y = points(2,:);
Xdiff = bsxfun(#minus, X.', X);
Ydiff = bsxfun(#minus, Y.', Y);
dists = sqrt(Xdiff.^2 + Ydiff.^2);
dists(tril(ones(numel(objects))==1)) = NaN;
[I,J] = find(dists < 300);
codes = [[objects(I).code].' [objects(J).code].'];
Toy Example
Here's an example that we can use to verify if what we have is correct:
objects(1).centre = [1868 1236];
objects(2).centre = [2000 1000];
objects(3).centre = [1900 1300];
objects(4).centre = [3000 2000];
objects(1).code = 33;
objects(2).code = 34;
objects(3).code = 35;
objects(4).code = 99;
I initialized 4 objects with different centroids and different codes. Let's see what the dists array gives us after we compute it:
>> format long g
>> dists
dists =
NaN 270.407100498489 71.5541752799933 1365.69396278961
NaN NaN 316.227766016838 1414.2135623731
NaN NaN NaN 1303.84048104053
NaN NaN NaN NaN
I intentionally made the last point farther than any of the other three points to ensure that we can show cases where there are points not near other ones.
As you can see, points (1,2) and (1,3) are all near each other, which is what we get when we complete the rest of the code. This corresponds to objects 33, 34 and 35 with pairings of (33,34) and (33,35). Points with codes 34 and 35 I made slightly smaller, but they are still greater than the 300 pixel threshold, so they don't count either:
>> codes
codes =
33 34
33 35
Now, if you want to display this in a prettified format, perhaps use a for loop:
for vec = codes.'
fprintf('Object with code %d interacted with object with code %d\n', vec(1), vec(2));
end
This for loop is a bit tricky. It's a little known fact that for loops can also accept matrices and the index variable gives you one column of each matrix at a time from left to right. Therefore, I transposed the codes array so that each pair of unique codes becomes a column. I just access the first and second element of each column and print it out.
We get:
Object with code 33 interacted with object with code 34
Object with code 33 interacted with object with code 35

Checking equality of row elements in Matlab?

I have a matrix A in Matlab of dimension mxn. I want to construct a vector B of dimension mx1 such that B(i)=1 if all elements of A(i,:) are equal and 0 otherwise. Any suggestion? E.g.
A=[1 2 3; 9 9 9; 2 2 2; 1 1 4]
B=[0;1;1;0]
One way with diff -
B = all(diff(A,[],2)==0,2)
Or With bsxfun -
B = all(bsxfun(#eq,A,A(:,1)),2)
Here's another example that's a bit more obfuscated, but also does the job:
B = sum(histc(A,unique(A),2) ~= 0, 2) == 1;
So how does this work? histc counts the frequency or occurrence of numbers in a dataset. What's cool about histc is that we can compute the frequency along a dimension independently, so what we can do is calculate the frequency of values along each row of the matrix A separately. The first parameter to histc is the matrix you want to compute the frequency of values of. The second parameter denotes the edges, or which values you are looking at in your matrix that you want to compute the frequencies of. We can specify all possible values by using unique on the entire matrix. The next parameter is the dimension we want to operate on, and I want to work along all of the columns so 2 is specified.
The result from histc will give us a M x N matrix where M is the total number of rows in our matrix A and N is the total number of unique values in A. Next, if a row contains all equal values, there should be only one value in this row where all of the values were binned at this location where the rest of the values are zero. As such, we determine which values in this matrix are non-zero and store this into a result matrix, then sum along the columns of the result matrix and see if each row has a sum of 1. If it does, then this row of A qualifies as having all of the same values.
Certainly not as efficient as Divakar's diff and bsxfun method, but an alternative since he took the two methods I would have used :P
Some more alternatives:
B = var(A,[],2)==0;
B = max(A,[],2)==min(A,[],2)

Finding maximum/minimum distance of two rows in a matrix using MATLAB

Say we have a matrix m x n where the number of rows of the matrix is very big. If we assume each row is a vector, then how could one find the maximum/minimum distance between vectors in this matrix?
My suggestion would be to use pdist. This computes pairs of Euclidean distances between unique combinations of observations like #seb has suggested, but this is already built into MATLAB. Your matrix is already formatted nicely for pdist where each row is an observation and each column is a variable.
Once you do apply pdist, apply squareform so that you can display the distance between pairwise entries in a more pleasant matrix form. The (i,j) entry for each value in this matrix tells you the distance between the ith and jth row. Also note that this matrix will be symmetric and the distances along the diagonal will inevitably equal to 0, as any vector's distance to itself must be zero. If your minimum distance between two different vectors were zero, if we were to search this matrix, then it may possibly report a self-distance instead of the actual distance between two different vectors. As such, in this matrix, you should set the diagonals of this matrix to NaN to avoid outputting these.
As such, assuming your matrix is A, all you have to do is this:
distValues = pdist(A); %// Compute pairwise distances
minDist = min(distValues); %// Find minimum distance
maxDist = max(distValues); %// Find maximum distance
distMatrix = squareform(distValues); %// Prettify
distMatrix(logical(eye(size(distMatrix)))) = NaN; %// Ignore self-distances
[minI,minJ] = find(distMatrix == minDist, 1); %// Find the two vectors with min. distance
[maxI,maxJ] = find(distMatrix == maxDist, 1); %// Find the two vectors with max. distance
minI, minJ, maxI, maxJ will return the two rows of A that produced the smallest distance and the largest distance respectively. Note that with the find statement, I have made the second parameter 1 so that it only returns one pair of vectors that have this minimum / maximum distance between each other. However, if you omit this parameter, then it will return all possible pairs of rows that share this same distance, but you will get duplicate entries as the squareform is symmetric. If you want to escape the duplication, set either the upper triangular half, or lower triangular half of your squareform matrix to NaN to tell MATLAB to skip searching in these duplicated areas. You can use MATLAB's tril or triu commands to do that. Take note that either of these methods by default will include the diagonal of the matrix and so there won't be any extra work here. As such, try something like:
distValues = pdist(A); %// Compute pairwise distances
minDist = min(distValues); %// Find minimum distance
maxDist = max(distValues); %// Find maximum distance
distMatrix = squareform(distValues); %// Prettify
distMatrix(triu(true(size(distMatrix)))) = NaN; %// To avoid searching for duplicates
[minI,minJ] = find(distMatrix == minDist); %// Find pairs of vectors with min. distance
[maxI,maxJ] = find(distMatrix == maxDist); %// Find pairs of vectors with max. distance
Judging from your application, you just want to find one such occurrence only, so let's leave it at that, but I'll put that here for you in case you need it.
You mean the max/min distance between any 2 rows? If so, you can try that:
numRows = 6;
A = randn(numRows, 100); %// Example of input matrix
%// Compute distances between each combination of 2 rows
T = nchoosek(1:numRows,2); %// pairs of indexes for all combinations of 2 rows
for k=1:length(T)
d(k) = norm(A(T(k,1),:)-A(T(k,2),:));
end
%// Find min/max distance
[~, minIndex] = min(d);
[~, maxIndex] = max(d);
T(minIndex,:) %// Displays indexes of the 2 rows with minimum distance
T(maxIndex,:) %// Displays indexes of the 2 rows with maximum distance

multiplying large matrix elements results in infinite

I am supposed to combine all the matrix into one, which concatenate horizontally by
matrix = [matrix1 matrix2 matrix3];
now i have to find the mean of the matrix which is 32 x 2039 dimensions.
i tried looping through each row and using mean for the whole elements in that row multipled and divided by the number of elements which is 2039.
answer i get is -Inf, all the time.
help would be appreciated.
thanks
my code what i could remember in case
[r, c] = size(matrix);
for i = 1:r
rowvalues = matrix(i,[1:c]);
mean(i,1) = mean2(rowvalues); %or mean(rowvalues,2);
end
results in -Inf.
my aim is to calculate the mean of the matrix which should be 39 X 1 dimensions.
thanks
When an element of a row is -Inf, the whole row will have a mean=-Inf.
I suggest you check this with the following code:
% The indices of the occurences of -Inf in matrix
mInfIndices=(matrix==-Inf);
% Does the row contain an -Inf?
mInfInRows=sum(mInfIndices,2)>0;
disp(mInfInRows);
This way you will see which rows contain a -Inf.