Obtain location of maximum inside a 3D matrix - matlab

How can I get a maximum of a three-dimensional matrix (which was previously two-dimensional and converted to a three-dimensional matrix by reshape) in MATLAB so that I can then get the position of that maximum value in the matrix?
I wrote the following code, but unfortunately the dimensions obtained for the maximum values are larger than the dimensions of the matrix.
mxshirin=max(max(frvrdin))
[X,Y,Z]=size(frvrdin)
[o,i]=find(frvrdin==mxshirin)
xo=size(o)
xi=size(i)

If frvrdin is 3D, max(max(frvrdin)) will be a 1x1x3 vector:
frvrdin = rand(3,3,3);
max(max(frvrdin))
ans(:,:,1) =
0.8235
ans(:,:,2) =
0.9502
ans(:,:,3) =
0.7547
Don't nest max() functions, simply use the 'all' switch to take the max of the entire matrix at once.
max(frvrdin,[],'all')
ans =
0.9340
If you're on an older MATLAB, use column flattening: max(frvrdin(:)).
You can't use the automated location output of max [val,idx]=max() on more than two dimensions, so use find and ind2sub:
frvrdin = rand(3,3,3);
val = max(frvrdin,[],'all'); % Find maximum over all dims
idx = find(abs(frvrdin-val)<1e-10); % Compare within tolerance
[row,col,page] = ind2sub(size(frvrdin),idx); % Get subscript indices
where row is the index into your first dimension, col into the second and finally page into the third.

Related

Fill a zeros matrix with specific numbers of 1

I'm facing a problem. I have a zeros matrix 600x600. I need to fill this matrix with 1080 1s randomly. Any suggestions?
Or, use the intrinsic routine randperm thusly:
A = zeros(600);
A(randperm(600^2,1080)) = 1;
A = sparse(600,600); %// set up your matrix
N=1080; %// number of desired ones
randindex = randi(600^2,N,1); %// get random locations for the ones
while numel(unique(randindex)) ~= numel(randindex)
randindex = randi(600^2,N,1); %// get new random locations for the ones
end
A(randindex) = 1; %// set the random locations to 1
This utilises randi to generate 1080 numbers randomly between 1 and 600^2, i.e. all possible locations in your vectors. The while loop is there in case it happens that one of the locations occurs twice, thus ending up with less than 1080 1.
The reason you can use a single index in this case for a matrix is because of linear indexing.
The big performance difference with respect to the other answers is that this initialises a sparse matrix, since 1080/600^2 = 0.3% is very sparse and will thus be faster. (Thanks to #Dev-iL)
This is one way to do it,
N = 1080; % Number of ones
M = zeros(600); % Create your matrix
a = rand(600^2,1); % generate a vector of randoms with the same length as the matrix
[~,asort] = sort(a); % Sorting will do uniform scrambling since uniform distribution is used
M(asort(1:N)) = 1; % Replace first N numbers with ones.

Distance between any combination of two points

I have 100 coordinates in a variable x in MATLAB . How can I make sure that distance between all combinations of two points is greater than 1?
You can do this in just one simple line, with the functions all and pdist:
if all(pdist(x)>1)
...
end
Best,
First you'll need to generate a matrix that gives you all possible pairs of coordinates. This post can serve as inspiration:
Generate a matrix containing all combinations of elements taken from n vectors
I'm going to assume that your coordinates are stored such that the columns denote the dimensionality and the rows denote how many points you have. As such, for 2D, you would have a 100 x 2 matrix, and in 3D you would have a 100 x 3 matrix and so on.
Once you generate all possible combinations, you simply compute the distance... which I will assume it to be Euclidean here... of all points and ensure that all of them are greater than 1.
As such:
%// Taken from the linked post
vectors = { 1:100, 1:100 }; %// input data: cell array of vectors
n = numel(vectors); %// number of vectors
combs = cell(1,n); %// pre-define to generate comma-separated list
[combs{end:-1:1}] = ndgrid(vectors{end:-1:1}); %// the reverse order in these two
%// comma-separated lists is needed to produce the rows of the result matrix in
%// lexicographical order
combs = cat(n+1, combs{:}); %// concat the n n-dim arrays along dimension n+1
combs = reshape(combs,[],n); %// reshape to obtain desired matrix
%// Index into your coordinates array
source_points = x(combs(:,1), :);
end_points = x(combs(:,2), :);
%// Checks to see if all distances are greater than 1
is_separated = all(sqrt(sum((source_points - end_points).^2, 2)) > 1);
is_separated will contain either 1 if all points are separated by a distance of 1 or greater and 0 otherwise. If we dissect the last line of code, it's a three step procedure:
sum((source_points - end_points).^2, 2) computes the pairwise differences between each component for each pair of points, squares the differences and then sums all of the values together.
sqrt(...(1)...) computes the square root which gives us the Euclidean distance.
all(...(2)... > 1) then checks to see if all of the distances computed in Step #2 were greater than 1 and our result thus follows.

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

Initializing a matrix with a certain value in matlab

I have this matrix A of size 100x100. Now I have another vector Z=(1,24,5,80...) which has 100 elements. it is a column vector with 100 elements. Now for each row of the matrix A, I want its A(i,j) element to be 1 where i is the row from 1:100 and j is the column which is given by Z
So the elements that should be 1 should be
1,1
2,24
3,5
4,80
and so on
I know I can do it using a loop. But is there a direct simple way I mean one liner?
A matrix that has 100 non-zero elements out of 10000 (so only 1% non-zero) in total is best stored as sparse. Use the capability of matlab.
A = sparse(1:100,Z,1,100,100);
This is a nice, clean one-linear, that results in a matrix that will be stored more efficiently that a full matrix. It can still be used for matrix multiplies, and will be more efficient at that too. For example...
Z = randperm(100);
A = sparse(1:100,Z,1,100,100);
whos A
Name Size Bytes Class Attributes
A 100x100 2408 double sparse
This is a reduction in memory of almost 40 to 1. And, while the matrix is actually rather small as these things go, it is still faster to use it as sparse.
B = rand(100);
timeit(#() B*A)
ans =
4.5717e-05
Af = full(A);
timeit(#() B*Af)
ans =
7.4452e-05
Had A been 1000x1000, the savings would have been even more significant.
If your goal is a full matrix, then you can use full to convert it to a full matrix, or accumarray is an option. And if you want to insert values into an existing array, then use sub2ind.
One way to do it is to convert the values in Z to absolute indices in A using sub2ind, and then use vector indexing:
idx = sub2ind(size(A), 1:numel(Z), Z);
A(idx) = 1;
or simply in a one-liner:
A(sub2ind(size(A), 1:numel(Z), Z)) = 1;

2d matrix histogram in matlab that interprets each column as a separate element

I have a 128 x 100 matrix in matlab, where each column should be treated as a separate element. Lets call this matrix M.
I have another 128 x 2000 matrix(called V) composed of columns from matrix M.
How would I make a histogram that maps the frequency of each column being used in the second matrix?
hist(double(V),double(M)) gives the error:
Error using histc
Edge vector must be monotonically
non-decreasing.
what should I be doing?
Here is an example. We start with data that resembles what you described
%# a matrix of 100 columns
M = rand(128,100);
sz = size(M);
%# a matrix composed of randomly selected columns of M (with replacement)
V = M(:,randi([1 sz(2)],[1 2000]));
Then:
%# map the columns to indices starting at 1
[~,~,idx] = unique([M,V]', 'rows', 'stable');
idx = idx(sz(2)+1:end);
%# count how many times each column occurs
count = histc(idx, 1:sz(2));
%# plot histogram
bar(1:sz(2), count, 'histc')
xlabel('column index'), ylabel('frequency')
set(gca, 'XLim',[1 sz(2)])
[Lia,Locb] = ismember(A,B,'rows') also returns a vector, Locb,
containing the highest index in B for each row in A that is also a row
in B. The output vector, Locb, contains 0 wherever A is not a row of
B.
ismember with the rows argument can identify which row of one matrix the rows of another matrix come from. Since it works on rows, and you are looking for columns, just transpose both matrices.
[~,Locb]=ismember(V',M');
histc(Locb)