Replacing NaNs with zero in a matrix within a cell array.

68 views (last 30 days)
How to replace NaNs with 0 in a cell array that has the following anatomy 13x1 cell, Each cell is of size 63x63[double]. the cell name is 'a'.
Any help would be appreciated, Thank you in advance.

Accepted Answer

Walter Roberson
Walter Roberson on 22 Jan 2019
a = cellfun(@(M) subsasgn(M, substruct('()', {isnan(M)}), 0), a, 'uniform', 0);
No loop needed... just ugly code.
  3 Comments
James Spalding
James Spalding on 19 Oct 2022
Hi Guys, I have a similiar problem but am getting errors prior to running from subsasgn:
"output must be assigned to a variable"
and after running get :
"Error using cellfun
Non-scalar in Uniform output, at index 1, output 1.
Set 'UniformOutput' to false."
I think it might be i don't understand the "M" variable which is used in the above solution. I've attached my cell variable {17x1} with uniform 362x292 matrices, also of note I am replacing the NaNs with a meaningless large number. I have tried switiching around M a destination variable as well as the call variable with NaNs.
I've attached the cell vairable and the code is below.
Any help here is greatly appreciated!
RvarNnan1 = cellfun(@(M) subsasgn(M, substruct('()', {isnan(M)}), 123000), RvarNnan1, 'UniformOutput', 123000);
Walter Roberson
Walter Roberson on 21 Oct 2022
@James Spalding The number after the keyword 'UniformOutput' is treated as a logical switch. It is tested for being either 0 (meaning No, Not uniform output) or non-zero (meaning Yes, uniform output). So when you changed from 'UniformOutput', 0 (not uniform output) to 'UniformOutput', 123000 you were switching to "yes, uniform output". Which is not correct for this situation.
The M variable is a "dummy parameter".
a = cellfun(@(M) subsasgn(M, substruct('()', {isnan(M)}), 0), a, 'uniform', 0);
means that each entry inside the cell named a is to be processed, with the content of each cell passed in turn as the first parameter to the anonymous function
@(M) subsasgn(M, substruct('()', {isnan(M)}), 0)
That anonymous function definition means that each time the anonymous function is executed, that a single parameter is to be accepted as input, and that everywhere inside the body of the code that the name M occurs it is to be replaced with what was passed in. The function handle is almost exactly equivalent to
@(varargin) subsasgn(varargin{1}, substruct('()', {isnan(varargin{1})}), 0)
-- that is, that the name of the variable M is not relevant (in nearly all conditions), that what is important is that it is the first parameter passed in that is being referred to, and what was passed in to the anonymous function is to be passed to first isnan() and later subsasgn() .
The reasons it is not exactly equivalent: (A) the @(varargin) version accepts extra parameters whereas the @(M) version errors if extra parameters are passed to the function; and (B) in the case where a named parameter is used, if a function is called that uses inputname then the name of the dummy parameter M can be retrieved, whereas if varargin is used, inputname() will return empty.
Functionally a = cellfun(@(M) subsasgn(M, substruct('()', {isnan(M)}), 0), a, 'uniform', 0); is equivalent to
if exist('M', 'var')
SomeTemporaryInternalVariableName = M;
SomeOtherTemporaryInternalVariableName = true;
else
SomeOtherTemporaryInternalVariableName = false;
end
a = cell(size(a));
for K = 1 : numel(a)
M = a{K};
M = subsasgn(M, substruct('()', {isnan(M)}, 0);
a{K} = M;
end
if SomeOtherTemporaryInternalVariableName
M = SomeTemporaryInternalVariableName;
clear SomeTemporaryInternalVariableName
end
clear SomeOtherTemporaryInternalVariableName
which is to say, that the name M is used temporarily to hold the element during the calculation, and afterwards if M existed already, M is restored to its previous value.
M is not the name of the variable you are trying to work with.
The adjusted code for you should be
RvarNnan1 = cellfun(@(M) subsasgn(M, substruct('()', {isnan(M)}), 123000), RvarNnan1, 'UniformOutput', 0);
but you should consider instead doing
RvarNnan1 = cellfun(@(M) fillmissing(M, 'constant', 123000), RvarNnan1, 'UniformOutput', 0);
as suggested by @Andy Campbell

Sign in to comment.

More Answers (2)

Omer Yasin Birey
Omer Yasin Birey on 22 Jan 2019
Edited: Omer Yasin Birey on 22 Jan 2019
% a = cell(13,1);
% %initializing the values
% for i = 1:length(a)
% a{i} = nan(63,63);
% end
%removing the nans
for k = 1:size(a,1)
for j = 1:size(a,2)
a{k,j}(isnan(a{k,j}))=0;
end
end

Andy Campbell
Andy Campbell on 1 Mar 2019
Edited: Andy Campbell on 1 Mar 2019
The fillmissing function is built for this, you just need to use cellfun since each of these doubles are included in the cell array.
nanless = cellfun(@(c) fillmissing(c,'constant',0), a,'UniformOutput',false)
If you don't want to use cellfun, since it looks like you data is all uniform you can also do this by putting each cell into an array, applyin fillmissing, and then reshaping it back into the cell array:
array = [a{:}]; % This works because they are all 63x63
array = fillmissing(array,'constant',0);
a = mat2cell(array, 63, ones(1,13)*63)
and of course this can all be one-lined
a = mat2cell(fillmissing([a{:}],'constant',0), 63, ones(1,13)*63);

Categories

Find more on Line Plots 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!