Getting row and column numbers of valid elements in a matrix - matlab

I have a 3x3 matrix, populated with NaN and values of a variable:
NaN 7 NaN
5 NaN 0
NaN NaN 4
matrix = [NaN 7 NaN; 5 NaN 0; NaN NaN 4]
I would like to get the row and column numbers of non-NaN cells and put them in a matrix together with the value of the variable. That is, I would like to obtain the following matrix:
row col value
1 2 7
2 1 5
2 3 0
3 3 4
want = [1 2 7; 2 1 5; 2 3 0; 3 3 4]
Any help would be highly appreciated.

This can be done without loops:
[jj, ii, kk] = find((~isnan(matrix).*(reshape(1:numel(matrix), size(matrix)))).');
result = [ii jj matrix(kk)];
The trick is to multiply ~isnan(matrix) by a matrix of indices so that the third output of find gives the linear index of non-NaN entries. The transpose is needed to have the same order as in the question.

The following should work!
[p,q]=find(~isnan(matrix)) % Loops through matrix to find indices
want = zeros(numel(p),3) % three columns you need with same number of rows as p
for i=1:numel(p)
want[i,:] = [p(i) q(i) matrix(p(i), matrix(i))]
end
Should give you the correct result which is:
2 1 5
1 2 7
2 3 0
3 3 4

If you don't mind the ordering of the rows, you can use a simplified version of Luis Mendo's answer:
[row, col] = find(~isnan(matrix));
result = [row(:), col(:), matrix(~isnan(matrix))];
Which will result in:
2 1 5
1 2 7
2 3 0
3 3 4

Related

Matlab: combining multiple matrices row-wise

I have some data in 10 matrices. Each matrix has a different number of rows, but the same number of columns.
I want to combine all 10 matrices to one matrix row-wise, interleaved, meaning the rows in that matrix will look like:
row 1 from matrix 0
...
row 1 from matrix 9
row 2 from matrix 0
...
row 2 from matrix 9
...
Example (with 3 matrices):
Matrix 1: [1 2 3 ; 4 5 6; 7 8 9]
Matrix 2: [3 2 1 ; 6 5 4]
Matrix 3: [1 1 1 ; 2 2 2 ; 3 3 3]
Combined matrix will be: [1 2 3 ; 3 2 1 ; 1 1 1 ; 4 5 6 ; 6 5 4 ; 2 2 2 ; 7 8 9 ; 3 3 3]
You can download the function interleave2 here https://au.mathworks.com/matlabcentral/fileexchange/45757-interleave-vectors-or-matrices
z = interleave2(a,b,c,'row')
you can see the way the function works in the source code of course
Here's a general solution that allows you to place however many matrices you want (with matching number of columns) into the starting cell array Result:
Result = {Matrix1, Matrix2, Matrix3};
index = cellfun(#(m) {1:size(m, 1)}, Result);
[~, index] = sort([index{:}]);
Result = vertcat(Result{:});
Result = Result(index, :);
This will generate an index vector 1:m for each matrix, where m is its number of rows. By concatenating these indices and sorting them, we can get a new index that can be used to sort the rows of the vertically-concatenated set of matrices so that they are interleaved.

Creating cumulative matrix which accounts for column start points

I have a simple example matrix as follows: (The actual matrix I'm working on is 674x11 and is not simply all '1' elements).
a =
1 1 1 NaN NaN
1 1 1 NaN NaN
1 1 1 1 NaN
1 1 1 1 1
1 1 1 1 1
I want to create a cumulative matrix which accounts for the fact that numeric elements start in each column at different rows. I want to achieve this by replacing the NaN value above the first numeric element in each column with the mean of that row.
So instead of:
cumsum(a)=
1 1 1 NaN NaN
2 2 2 NaN NaN
3 3 3 1 NaN
4 4 4 2 1
5 5 5 3 2
what I want to achieve is:
cumsum(a) =
1 1 1 NaN NaN
2 2 2 2 NaN
3 3 3 3 3
4 4 4 4 4
5 5 5 5 5
where element (2,4) is the mean of a(2,1:3) and element (3,5) is the mean of a(3,1:4).
You can compute the mean of each row (ignoring the NaN values) by using nanmean. We can then use find to identify the row in which each NaN is and replace the values with the mean of that row. Then we can follow that up with the cumsum operation
% Get the rows of each NaN value
bool = isnan(a);
[row,col] = find(bool);
% Compute the mean value of each row
rowmeans = nanmean(a, 2);
% Replace the NaN values with their row means
a(bool) = rowmeans(row);
% Perform the cumulative sum
result = cumsum(a);
If you want to leave the initial NaN values as NaN values afterwards, then you can follow it up with
result(bool) = NaN;

How can I remove NaN values from a dataset? [duplicate]

This question already has answers here:
Is there any general way to remove NaNs from a matrix?
(5 answers)
Closed 6 years ago.
New to MATLAB, any help with this would be appreciated.
I have a dataset that is 1000 elements in 1 column, and most of the elements are numbers but some are NaN's. Is there a way I can, 1. Find them, and 2. Remove them and put them in a variable (or just remove them)?
Would I have to do this the reverse way and find and remove the non-NaN's (the numbers) and store them in a variable?
Use logical indexing to extract the elements that are not NaN and then store them anywhere you like. Here's how it works. If x is your column vector containing NaN, y = ~isnan(x) will give a logical vector y such that |y|=|x| and y(i) is 1 iff x(1) is not NaN. You can use this logical vector to extract non NaN elements:
x = [1 2 3 NaN 5 6 NaN NaN 9];
y = ~isnan(x); % now y is [1 1 1 0 1 1 0 0 1]
x = x(y) % now x is [1 2 3 5 6 9]
Logical indexing is powerful and efficient. You could also say:
x = [1 2 3 NaN 5 6 NaN NaN 9];
x(isnan(x)) = -1 % now x is [1 2 3 -1 5 6 -1 -1 9]
For more information on logical indexing see the official Matlab documentation here.
A option equivalent to #sadeghmir's answer:
x = [1 2 3 NaN 5 6 NaN NaN 9];
x(x==NaN)=[];
>x
1 2 3 5 6 9

Getting indices of sorted elements of matrix

I am trying to get the sort of row and column according to the value of matrix.
for example, if the matrix is
A = [3 4 7; 9 8 6; 2 1 5]
it should output
2 1
2 2
1 3
2 3
3 3
1 2
1 1
3 1
3 2
I think that should be simple, but I do not have an idea about how to handle that.
Yes it is indeed very simple.
%sort the vector instead of matrix to get linear indices
[~,ind]=sort(A(:),'descend')
%convert the linear indices to [row,col] subscripts
[I,J]=ind2sub(size(A),ind)
%display desired answer
[I J]
To delete rows which have same value in both the columns:
A(A(:,1)==A(:,2),:)=[]

Find row-wise minima in sparse matrix

I would like to get the minimum nonzero values per row in a sparse matrix. Solutions I found for dense matrices suggested masking out the zero values by setting them to NaN or Inf. However, this obviously doesn't work for sparse matrices.
Ideally, I should get a column vector of all the row-wise minima, as I would get with
minValues = min( A, [], 2);
Except, obviously, using min leaves me with an all-zeros column vector due to the sparsity. Is there a solution using find?
This is perfect for accumarray. Consider the following sparse matrix,
vals = [3 1 1 9 7 4 10 1]; % got this from randi(10,1,8)
S = sparse([1 3 4 4 5 5 7 9],[2 2 3 6 7 8 8 11],vals);
Get the minimum value for each row, assuming 0 for empty elements:
[ii,jj] = find(S);
rowMinVals = accumarray(ii,nonzeros(S),[],#min)
Note that rows 4 and 5 of rowMinVals, which are the only two rows of S with multiple nonzero values are equal to the min of the row:
rowMinVals =
3
0
1
1 % min([1 9]
4 % min([7 4]
0
10
0
1
If the last row(s) of your sparse matrix do not contain any non-zeros, but you want your min row value output to reflect that you have numRows, for example, change theaccumarray command as follows,
rowMinVals = accumarray(ii,nonzeros(S),[numRows 1],#min).
Also, perhaps you also want to avoid including the default 0 in the output. One way to handle that is to set the fillval input argument to NaN:
rowMinVals = accumarray(ii,nonzeros(S),[numRows 1],#min,NaN)
rowMinVals =
3
NaN
1
1
4
NaN
10
NaN
1
NaN
NaN
NaN
Or you can keep using a sparse matrix with the fifth input argument, issparse:
>> rowMinVals = accumarray(ii,nonzeros(S),[],#min,[],true)
rowMinVals =
(1,1) 3
(3,1) 1
(4,1) 1
(5,1) 4
(7,1) 10
(9,1) 1