MATLAB Answers

How do I remove all fields of a structure that have at least one NaN?

조회 수: 4(최근 30일)
I have a structure S with n fields, field1, field2 etc.. How do I remove those fields that have at least one NaN?
Thank you

  댓글 수: 0

로그인 to comment.

채택된 답변

Walter Roberson
Walter Roberson 1 Apr 2020
The question does not permit us to assume that the struct fields are exclusively numeric or that the fields will not be compound data types, or that the initial structure is a scalar structure. We must assume that it might be a non-scalar structure, containing nested data types, and that for any given field at the top level, if there is a nan anywhere inside the object in any of the array dimensions, that the field must be removed from all struct array locations.
Taking this into consideration, you need a real function, and it is probably easiest to make the function recursive.
Under some restricted conditions, this code could be simplified.
function S = structrmnan(S)
if isstruct(S)
Sfields = fieldnames(S);
tc = struct2cell(S);
cn = cellfun(@containsNan, tc);
mask = any(cn, 2:ndims(cn));
tc(any(cn, 2:ndims(cn)),:) = [];
S = reshape(cell2struct(tc, Sfields(~mask), 1), size(S));
end
end
function tf = containsNan(V)
if isnumeric(V)
tf = nnz(isnan(V))>0;
elseif ischar(V) || islogical(V)
tf = false;
elseif ~isscalar(V)
tf = any(arrayfun(@containsNan, V(:)));
elseif iscell(V)
tf = any(cellfun(@containsNan, V(:)));
elseif isstruct(V)
tf = any(structfun(@containsNan, V(:)));
else
%for example there could be a NaN inside UserData of an array
%of line objects
error('Needs to be extended to handle datatype "%s"', class(V))
end
end

  댓글 수: 3

Giovanni Barbarossa
Giovanni Barbarossa 1 Apr 2020
Thank you all. I have attached the structure. The previous suggestions do not seem to work. I will try Mr. Robenson suggestion now. I think the datetime field is complicating things.
Walter Roberson
Walter Roberson 1 Apr 2020
Extended to handle datetime, duration, calendarDuration, categorical, string, table
(I do not promise that all cases with table are handled; for example it would not surprise me if this version failed for a table that contained a nested table.)
function S = structrmnan(S)
if isstruct(S)
Sfields = fieldnames(S);
tc = struct2cell(S);
cn = cellfun(@containsNan, tc);
mask = any(cn, 2:ndims(cn));
tc(mask,:) = [];
S = reshape(cell2struct(tc, Sfields(~mask), 1), size(S));
end
end
function tf = containsNan(V)
if ischar(V) || islogical(V)
tf = false;
elseif isnumeric(V) || ...
isdatetime(V) || isduration(V) || iscalendarduration(V) || ...
iscategorical(V) || isstring(V) || istable(V)
tf = nnz(ismissing(V))>0;
elseif ~isscalar(V)
tf = any(arrayfun(@containsNan, V(:)));
elseif iscell(V)
tf = any(cellfun(@containsNan, V(:)));
elseif isstruct(V)
tf = any(structfun(@containsNan, V(:)));
else
error('Needs to be extended to handle datatype "%s"', class(V))
end
end
Giovanni Barbarossa
Giovanni Barbarossa 2 Apr 2020
Thank you very much. It works perfectly.

로그인 to comment.

추가 답변(2개)

darova
darova 1 Apr 2020
편집: darova 1 Apr 2020
Try rmfield
a = [1 nan 3];
bb = [1 2 3];
S.a = a;
S.bb = bb;
S
nms = fieldnames(S);
for i = 1:length(nms)
f = getfield(S,nms{i});
if isnan(sum(f))
S = rmfield(S,nms{i});
end
end
S

  댓글 수: 5

표시 이전 댓글 수: 2
Giovanni Barbarossa
Giovanni Barbarossa 1 Apr 2020
Because I want to remove all fields that have at least one NaN, I would have expected a simpler solution. I thought about using something like rmmissing, which I know does not work for structures. Also something like a combination of isnan and any.
Anyway, it does not work because there is an error using sum: Invalid data type. First argument must be numeric or logical.
Thanks
darova
darova 1 Apr 2020
  • I would have expected a simpler solution
Im a simple man
  • Also something like a combination of isnan and any.
As you wish
if any(isnan(f))
James Tursa
James Tursa 1 Apr 2020
@Giovanni: For the invalid variable type, you can test for numeric. E.g.,
if isnumeric(f) && any(isnan(f(:)))

로그인 to comment.


Image Analyst
Image Analyst 1 Apr 2020
편집: Image Analyst 1 Apr 2020
If you want, you can try to use structfun() but it's rather cryptic. darova's solution is much more intuitive and readable.
By the way, I'd have used any() instead of sum(), k instead of i (since i is the imaginary variable), and dynamic field names:
S.a = [1, nan, 3];
S.bb = [1, 2, 3];
S
nms = fieldnames(S);
for k = 1:length(nms)
thisField = S.(nms{k});
if any(isnan(thisField))
S = rmfield(S, nms{k});
end
end
S

  댓글 수: 2

darova
darova 1 Apr 2020
thanks bro, appreciate your support
James Tursa
James Tursa 1 Apr 2020
Including the the type check here as well:
if isnumeric(thisField) && any(isnan(thisField(:)))

로그인 to comment.

이 질문에 답변하려면 로그인을(를) 수행하십시오.

태그


Translated by