Remove NaNs in matrices within cell array

5 views (last 30 days)
I have a matrix that has some data in its columns like this:
A = [1 NaN NaN 1 1; NaN NaN NaN 1 NaN; 1 1 NaN 1 NaN]
I want to extract the non NaN elements so that they are returned in a cell array where a cell holds the non NaN elements of the columns like this:
C = {[1;1],[1],[],[1;1;1],[1]}
This far I have tried to use the cellfun:
C = num2cell(A,1);
C(cellfun(@isnan,C, 'UniformOutput', false)) = [];
But i receive an error: Function 'subsindex' is not defined for values of class 'cell'.
I Managed to use for loop:
C = num2cell(A,1);
for i = 1:length(ct)
inds = isnan(ct{i});
ct{i}(inds) = [];
end
This does the trick, but I'm worried about the performance as A can be huge in my actual code.
Any help is more than welcome!
Edit: typo

Accepted Answer

Andrei Bobrov
Andrei Bobrov on 7 Nov 2013
Edited: Andrei Bobrov on 7 Nov 2013
out = cellfun(@(x)x(~isnan(x)),num2cell(A,1),'un',0);
with for-end loop
n = size(A,2);
out = cell(n,1);
for jj = 1:n
out{jj} = A(~isnan(A(:,jj)),jj);
end
with accumarray
s = size(A);
ii = ones(s(1),1)*(1:s(2));
out = accumarray(ii(:),A(:),[],@(x){x(~isnan(x))});
  1 Comment
Hannu K
Hannu K on 7 Nov 2013
Thank you! As it turns out, the for-loop approach is quicker.

Sign in to comment.

More Answers (6)

Matt J
Matt J on 7 Nov 2013
Edited: Matt J on 7 Nov 2013
This does the trick, but I'm worried about the performance as A can be huge in my actual code.
Cellfun is usually less efficient than a for-loop. It basically runs a for-loop internally, but in a slightly less efficient way than a direct for-loop.
Also, even though A is huge, length(ct) will not be, correct? If length(ct) is really huge, that's a bigger problem than the question of whether to use cellfun or for-loops. It means you'll have lots of data scattered discontiguously in RAM and access to the cell contents will be very slow.
  1 Comment
Hannu K
Hannu K on 7 Nov 2013
Thank you for the insight. I always thought that cellfun does some magic that outperforms the for loop.

Sign in to comment.


Matt J
Matt J on 7 Nov 2013
If all elements of A are either NaN or non-zero, then it would be better to convert to a sparse matrix, rather than use cell arrays
[i,j,s]=find(~isnan(A));
[m,n]=size(A);
A=sparse(i,j,s,m,n);

Matt J
Matt J on 7 Nov 2013
Yet another alternative,
map=~isnan(A);
[i,j]=find(map);
k=histc(j,1:size(A,2));
C=mat2cell(A(map),k,1).';

Azzi Abdelmalek
Azzi Abdelmalek on 7 Nov 2013
out1=arrayfun(@(x) A(~isnan(A(:,x)),x),1:size(A,2),'un',0)

David Sanchez
David Sanchez on 7 Nov 2013
for single line solution, A. Abdelmalek's is the solution. You can perform the same by using the following:
A = [3 NaN NaN 2 4; NaN NaN NaN 5 NaN; 6 7 NaN 8 NaN];
[rows cols] = size(A); % number of rows and columns in your matrix
D = mat2cell(A,rows,ones(1,cols)); % cell to hold your data
for k=1:numel(D)
C = ~isnan(D{k});
D{k}(C==0) = [];
end
It works with values different to 1 and the code is quite readable.

Bob Freeman
Bob Freeman on 7 Nov 2013
do find(NaN == 0)

Categories

Find more on Structures in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!