Removing NaN elements from a matrix - matlab

There is one NaN element per row, I want to remove it.
A=[NaN 1 2;
3 NaN 4;
NaN 5 6];
The desired output is:
[1 2;
3 4;
5 6]

A = [NaN 1 2 ; 3 NaN 4; NaN 5 6]
sz = size(A);
B = reshape(A', size(A,1)*size(A,2), 1);
B(isnan(B)) = [];
B = reshape(B, sz(2)-1, sz(1))'

I thought it could be done in one line, but I was wrong. See solution below:
Given (added row helps me debug my indexing below):
>> A = [NaN 1 2 ; 3 NaN 4; NaN 5 6; 7 8 NaN]
A =
NaN 1 2
3 NaN 4
NaN 5 6
7 8 NaN
Then:
>> Atrans = A';
>> B = reshape( Atrans(~isnan(Atrans)) ,[],size(Atrans,2))'
B =
1 2
3 4
5 6
7 8
Incidentally, the Matlab idiom of performing a simple logical check on an array within an logical indexing operation is very common and incredibly useful. The archetypical example is:
>> x(x>0) %This returns a 1D column vector of all values of x
%which are greater than 0, regardless of the initial
%size of x. Multidimensional inputs are unwrapped
%column-first
Everything else above is size and dimension handling.

Here it is - please note that the code is not robust. It assumes that indeed in every row there is a NaN element.
While it is not a vectorized solution, it has other advantages - like a clear code.
for i=1:size(A,1)
x = A(i,:);
x(isnan(x)) = [];
B(i,:) = x;
end
B
B =
1 2
3 4
5 6

Related

MATLAB: How can I cancel ("NaN" value) elements of a matrix based on another matrix's "NaN" values?

Let's suppose I have a matrix A=
1 2 3;
4 5 6;
7 8 9
and a matrix B=
1 NaN 3;
NaN 5 6;
7 NaN NaN
I want to cancel the same elements that are canceled in matrix B. It would be:
A2=
1 NaN 3;
NaN 5 6;
7 NaN NaN
How can I do that?
You could create the new matrix A2 such that each element is a2 = b - b + a.
This relies on the fact that NaN propagates through the expression evaluation, and b - b is essentially a no-op in all other instances.
It is also guaranteed never to overflow your type.

MATLAB: Construct matrix from selected matrix elements

I have a 3x3x3 matrix which contains a particular set of elements that I would like to extract. However, I would like for the elements to be ordered in a matrix after selecting them. An example is:
a(1,:,:)=1*[1 2 3; 4 5 6; 7 8 9];
a(2,:,:)=2*[1 2 3; 4 5 6; 7 8 9];
a(3,:,:)=3*[1 2 3; 4 5 6; 7 8 9];
a(a>1.0)
The condition a(a>1.0) gives me a vector of elements, but is there a way to order them in a matrix following their original ordering?
What would you like to do to the elements that don't satisfy your criteria?
You could do something like a(a<=1) = nan;
Suppose 2-D matrix for simplicity:
a = [1 2 3; ...
4 5 6];
Let's take only even values and keep them in their original shape:
a(mod(a, 2) == 0)
You might want:
2
4 6
However, in the world of matrix, is there such a matrix which has empty space? Yes, a sparse matrix. But, you must note that a sparse matrix is filled with 0 not just missing.
So, my suggestion is to replace other values with NaN
b = a; % just make a duplicate
b(mod(b, 2) == 1) = nan
b =
nan 2 nan
4 nan 6

how to join N vectors into matrix in matlab?

I tried looking this up, but don't really know what to look for...
I need to "table-join" N vectors, meaning,
to create a matrix in which every input vector has a row, and every possible entry has a column.
Also it would be nice to have a translation vector to has easy access to which column is responsible for which entry
for example
a = [3, 2, 4, 9]
b = [3, 1, 5, 9]
c = [2, 4, 9, 6]
then
join(a, b, c) =
[
3; 2; nan; 4; nan; 9; nan,
3; nan; 1; nan; 5; 9; nan,
nan; 2; nan; 4; nan; 9; 6,
]
with a translation vector
[3,2,1,4,5,9,6]
so if I find out something about the i'th column, I can easily know what that column represents.
I prefer the join operation to be able to take in n vectors (they can be of the same length), but 2 is also ok.
Also, on a second glance, this data representation seems a bit redundant at some points. Perhaps there is a better way to even represent the "join-matrix"
Thanks
Basically you want to construct your translation vector using all the possible unique inputs in the order that they were received. To do this, we can concatenate all of the inputs together than find the unique values.
values = cat(1, [3, 2, 4, 9], [3, 1, 5, 9], [2, 4, 9, 6])
%// 3 2 4 9
%// 3 1 5 9
%// 2 4 9 6
translationVector = unique(values, 'stable')
%// 3 2 1 4 5 9 6
Then we want to use ismember to return a logical array for any given input to specify which values of our translation vector are present in the input argument.
columns = ismember(translationVector, [3 2 4 9])
%// 1 1 0 1 0 1 0
We then want to set just those columns in the output matrix.
output(1, columns) = [3 2 4 9];
%// 3 2 NaN 4 NaN 9 NaN
%// NaN NaN NaN NaN NaN NaN NaN
%// NaN NaN NaN NaN NaN NaN NaN
We then repeat this for all of your input arrays.
Implementation
Here is some code that accomplishes that.
function [out, translationVector] = yourjoin(varargin)
%// Make sure all inputs are row vectors
varargin = cellfun(#(x)x(:).', varargin, 'uni', 0); %'
%// compute the translation vector
translationVector = unique(cat(1, varargin{:}), 'stable');
%// Pre-allocate your matrix of NaNs
out = nan(numel(varargin), numel(translationVector));
%// Fill in each row using each input argument
for k = 1:numel(varargin)
%// Identify columns that we have
toreplace = ismember(translationVector, varargin{k});
%// Set the values of those columns to the input values
out(k,toreplace) = varargin{k};
end
end
And then as a test:
a = [3 2 4 9];
b = [3 1 5 9];
c = [2 4 9 6];
D = yourjoin(a,b,c)
3 2 NaN 4 NaN 9 NaN
3 NaN 1 NaN 5 9 NaN
NaN 2 NaN 4 NaN 9 6

Generate a matrix with increasing values but NaN along the main diagonal?

There is likely a quick little trick for this problem, but I cannot find it. I would like code to produce the matrix in the following image:
Here's a way using logical indexing:
n = 4;
A = nan(n);
A(~eye(n)) = 1:n^2-n; %// Only replace values *not* on diagonal
A = A.'
A =
NaN 1 2 3
4 NaN 5 6
7 8 NaN 9
10 11 12 NaN
Here's one way using triu and tril:
n = 4;
A = reshape(1:n*(n-1),n-1,n).';
z = zeros(n,1);
A = [tril(A,-1) z]+[z triu(A)]+diag(NaN(n,1));
which, in this case for a 4-by-4 matrix, returns
A =
NaN 1 2 3
4 NaN 5 6
7 8 NaN 9
10 11 12 NaN
Here's another way just using reshape:
n = 4;
A = [reshape(1:n*(n-1),n,n-1);NaN(1,n-1)];
A = reshape([NaN;A(:)],n,n).'
Here's another way:
n = 4; %// matrix size
x = 1-eye(n);
x(:) = cumsum(x(:));
x = x.' + diag(NaN(1,n));
You can start from a nan matrix, find the linear indices of the diagonal, then fill up the rest of the elements with an incrementing range:
n=4;
A=nan(n);
inds=setdiff(1:n^2,sub2ind([n,n],1:n,1:n));
A(inds)=1:numel(inds);
A=A.'; %' transpose to get the matrix we need
The transpose in the end is necessary, as linear indexing goes column-first, but your specifics need a row-first assignment of matrix elements.
Result:
>> A
A =
NaN 1 2 3
4 NaN 5 6
7 8 NaN 9
10 11 12 NaN

Getting row and column numbers of valid elements in a matrix

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