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

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

Related

Matching matrices of different size and creating new matrix in MATLAB

I have a matrix A and B as the following:
A = [1 NaN 3 4 5 NaN NaN 8 9 10];
B = [2 6 7];
Matrix B has the same size as there are NaN values in matrix A (so 3x1 in this case).
I would like to replace the NaN values in the same order as the values appear in B. So the output should look like:
C = [1 2 3 4 5 6 7 8 9 10];
I can replace the NaN, if both matrices have the same size. For T = 10 and N = 1, I would use:
for t=1:T
for i=1:N
if A == NaN
C(t,i) = B;
else
C(t,i) = A(t,i);
end
end
end
However, I would like to know whether I could compare these matrices and replace the values even if the matrices are of different size? Saying differently, if A = NaN take the first value of B. For the next A = NaN take the second value in B.
You can simply do:
A(find(isnan(A))) = B; % store the result of find(...) to keep track of NaN indices
isnan() is the proper way of determining whether a value is NaN (since NaN ~= NaN), while find() returns the indices of A where an element is NaN in this case.
As per #Adiel's suggestion, you can use logical indexing instead to more compactly achieve the same result, provided you don't need the indices of NaN elements later on:
A(isnan(A)) = B;

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.

Replace non-NaN values with their row indices within matrix

I have the 4x2 matrix A:
A = [2 NaN 5 8; 14 NaN 23 NaN]';
I want to replace the non-NaN values with their associated indices within each column in A. The output looks like this:
out = [1 NaN 3 4; 1 NaN 3 NaN]';
I know how to do it for each column manually, but I would like an automatic solution, as I have much larger matrices to handle. Anyone has any idea?
out = bsxfun(#times, A-A+1, (1:size(A,1)).');
How it works:
A-A+1 replaces actual numbers in A by 1, and keeps NaN as NaN
(1:size(A,1)).' is a column vector of row indices
bsxfun(#times, ...) multiplies both of the above with singleton expansion.
As pointed out by #thewaywewalk, in Matlab R2016 onwards bsxfun(#times...) can be replaced by .*, as singleton expansion is enabled by default:
out = (A-A+1) .* (1:size(A,1)).';
An alternative suggested by #Dev-Il is
out = bsxfun(#plus, A*0, (1:size(A,1)).');
This works because multiplying by 0 replaces actual numbers by 0, and keeps NaN as is.
Applying ind2sub to a mask created with isnan will do.
mask = find(~isnan(A));
[rows,~] = ind2sub(size(A),mask)
A(mask) = rows;
Note that the second output of ind2sub needs to be requested (but neglected with ~) as well [rows,~] to indicate you want the output for a 2D-matrix.
A =
1 1
NaN NaN
3 3
4 NaN
A.' =
1 NaN 3 4
1 NaN 3 NaN
Also be careful the with the two different transpose operators ' and .'.
Alternative
[n,m] = size(A);
B = ndgrid(1:n,1:m);
B(isnan(A)) = NaN;
or even (with a little inspiration by Luis Mendo)
[n,m] = size(A);
B = A-A + ndgrid(1:n,1:m)
or in one line
B = A-A + ndgrid(1:size(A,1),1:size(A,2))
This can be done using repmat and isnan as follows:
A = [ 2 NaN 5 8;
14 NaN 23 NaN];
out=repmat([1:size(A,2)],size(A,1),1); % out contains indexes of all the values
out(isnan(A))= NaN % Replacing the indexes where NaN exists with NaN
Output:
1 NaN 3 4
1 NaN 3 NaN
You can take the transpose if you want.
I'm adding another answer for a couple of reasons:
Because overkill (*ahem* kron *ahem*) is fun.
To demonstrate that A*0 does the same as A-A.
A = [2 NaN 5 8; 14 NaN 23 NaN].';
out = A*0 + kron((1:size(A,1)).', ones(1,size(A,2)))
out =
1 1
NaN NaN
3 3
4 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

Removing NaN elements from a matrix

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