Reputation: 909
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?
Upvotes: 12
Views: 540
Reputation: 25232
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 .'
.
[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))
Upvotes: 8
Reputation: 112679
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 indicesbsxfun(@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.
Upvotes: 11
Reputation: 24169
I'm adding another answer for a couple of reasons:
kron
*ahem*) is fun.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
Upvotes: 2
Reputation: 19689
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.
Upvotes: 6