time | Calls | line |
---|
| | 1 | function IA = ismissingKernel(A,indicators,stdize,dataVars)
|
| | 2 | % ismissingKernel Helper function for ismissing and standardizeMissing
|
| | 3 | %
|
| | 4 | % FOR INTERNAL USE ONLY -- This feature is intentionally undocumented.
|
| | 5 | % Its behavior may change, or it may be removed in a future release.
|
| | 6 | %
|
| | 7 | % IA is either a logical array (the output of ismissing) or an array/table
|
| | 8 | % containing standardized entries.
|
| | 9 |
|
| | 10 | % Copyright 2016-2019 The MathWorks, Inc.
|
| | 11 |
|
< 0.001 | 2 | 12 | AisTable = matlab.internal.datatypes.istabular(A);
|
< 0.001 | 2 | 13 | if nargin <= 1
|
| | 14 | % ismissing(A)
|
< 0.001 | 2 | 15 | if ~AisTable
|
< 0.001 | 2 | 16 | IA = arraySwitch(A,false);
|
| | 17 | else
|
| | 18 | IA = false(size(A));
|
| | 19 | for jj = 1:width(A)
|
| | 20 | IA(:,jj) = arraySwitch(A.(jj),true);
|
| | 21 | end
|
< 0.001 | 2 | 22 | end
|
| | 23 | else
|
| | 24 | if ~AisTable
|
| | 25 | % ismissing(A,indicators)
|
| | 26 | % standardizeMissing(A,indicators)
|
| | 27 | indstruct = parseIndicators(indicators,false,stdize);
|
| | 28 | IA = arraySwitchIndicators(A,false,indstruct,stdize);
|
| | 29 | else
|
| | 30 | if nargin < 4
|
| | 31 | dataVars = 1:width(A);
|
| | 32 | end
|
| | 33 | indstruct = parseIndicators(indicators,true,stdize);
|
| | 34 | if ~stdize
|
| | 35 | % ismissing(A,indicators)
|
| | 36 | IA = false(size(A));
|
| | 37 | for jj = dataVars
|
| | 38 | IA(:,jj) = arraySwitchIndicators(A.(jj),true,indstruct,stdize);
|
| | 39 | end
|
| | 40 | else
|
| | 41 | % standardizeMissing(A,indicators)
|
| | 42 | % standardizeMissing(A,indicators,'DataVariables',dataVars)
|
| | 43 | IA = A;
|
| | 44 | for jj = dataVars
|
| | 45 | IA.(jj) = arraySwitchIndicators(A.(jj),true,indstruct,stdize);
|
| | 46 | end
|
| | 47 | end
|
| | 48 | end
|
< 0.001 | 2 | 49 | end
|
| | 50 | %--------------------------------------------------------------------------
|
| | 51 | function IA = arraySwitch(A,AinTable)
|
| | 52 | % Used for 1-input ismissing for arrays or table variables
|
| | 53 | if isfloat(A)
|
| | 54 | IA = isnan(A);
|
| | 55 | elseif builtin('ischar',A)
|
| | 56 | if ~AinTable
|
| | 57 | IA = A == ' '; % blank char
|
| | 58 | else
|
| | 59 | % Convert to string via helper for correct N-D char array behavior.
|
| | 60 | A = matlab.internal.math.charRows2string(A);
|
| | 61 | IA = ismissing(A);
|
| | 62 | end
|
| | 63 | elseif iscellstr(A)
|
| | 64 | IA = cellfun('isempty',A);
|
| | 65 | elseif builtin('isstring',A)
|
| | 66 | IA = ismissing(A);
|
| | 67 | elseif iscategorical(A)
|
| | 68 | IA = isundefined(A);
|
| | 69 | elseif isdatetime(A)
|
| | 70 | IA = isnat(A);
|
| | 71 | elseif (isduration(A) || iscalendarduration(A))
|
| | 72 | IA = isnan(A);
|
| | 73 | elseif (isinteger(A) || islogical(A))
|
| | 74 | IA = false(size(A));
|
| | 75 | else
|
| | 76 | if AinTable
|
| | 77 | IA = false(size(A)); % Ignore table variables of unsupported types
|
| | 78 | else
|
| | 79 | error(message('MATLAB:ismissing:FirstInputInvalid'));
|
| | 80 | end
|
| | 81 | end
|
| | 82 | if AinTable
|
| | 83 | IA = collapseIntoLogicalColumn(IA);
|
| | 84 | end
|
| | 85 | end
|
| | 86 | %--------------------------------------------------------------------------
|
| | 87 | function IA = arraySwitchIndicators(A,AinTable,ind,stdize)
|
| | 88 | % Indicators-based ismissing and standardizeMissing for arrays or tables
|
| | 89 | if isa(A,'double')
|
| | 90 | IA = ismissingApply(A,AinTable,ind,stdize,NaN,@ismissingNumeric,'Double');
|
| | 91 | elseif isa(A,'single')
|
| | 92 | IA = ismissingApply(A,AinTable,ind,stdize,NaN,@ismissingNumeric,'Single');
|
| | 93 | elseif ischar(A)
|
| | 94 | if ~AinTable
|
| | 95 | IA = ismissingApply(A,AinTable,ind,stdize,' ',@ismissingChar,'Char');
|
| | 96 | else
|
| | 97 | % Convert to string via helper for correct N-D char array behavior.
|
| | 98 | As = matlab.internal.math.charRows2string(A);
|
| | 99 | % Remove trailing whitespace. We want the ' ' indicator to match
|
| | 100 | % blank rows of any width, and a normal character row to match with
|
| | 101 | % the indicators regardless of how much trailing whitespace it has.
|
| | 102 | Ad = strip(As,'right');
|
| | 103 | IA = ismissingApply(Ad,AinTable,ind,false,[],@ismissingString,'CharInTable');
|
| | 104 | if stdize
|
| | 105 | As(IA) = string(NaN);
|
| | 106 | % Convert back to char via helper for correct N-D char array behavior.
|
| | 107 | IA = matlab.internal.math.string2charRows(As);
|
| | 108 | end
|
| | 109 | end
|
| | 110 | elseif iscellstr(A)
|
| | 111 | IA = ismissingApply(A,AinTable,ind,stdize,{''},@ismissingCellstr,'Cellstr');
|
| | 112 | elseif isstring(A)
|
| | 113 | IA = ismissingApply(A,AinTable,ind,stdize,string(NaN),@ismissingString,'String');
|
| | 114 | elseif iscategorical(A)
|
| | 115 | IA = ismissingApply(A,AinTable,ind,stdize,'',@ismissingCategorical,'Categorical');
|
| | 116 | if stdize && isfield(ind,'Categorical')
|
| | 117 | indTmp = ind.('Categorical');
|
| | 118 | indTmp = indTmp(~cellfun('isempty',indTmp) & ~strcmp(categorical.undefLabel,indTmp));
|
| | 119 | IA = removecats(IA,indTmp); % errors if second input is '' or '<undefined>'
|
| | 120 | end
|
| | 121 | elseif isdatetime(A)
|
| | 122 | IA = ismissingApply(A,AinTable,ind,stdize,NaT,@ismissingDatetime,'Datetime');
|
| | 123 | elseif isduration(A)
|
| | 124 | IA = ismissingApply(A,AinTable,ind,stdize,NaN,@ismissingDuration,'Duration');
|
| | 125 | elseif (isinteger(A) || islogical(A))
|
| | 126 | % Integer arrays match to double indicators or to integer indicators of
|
| | 127 | % exactly the same type of integer -- same behavior as ISMEMBER.
|
| | 128 | indTmp = {};
|
| | 129 | if isfield(ind,'IntegerLogical')
|
| | 130 | indTmp = ind.('IntegerLogical');
|
| | 131 | indTmp = indTmp(cellfun(@(x) isa(x,'double') || isa(x,class(A)),indTmp));
|
| | 132 | end
|
| | 133 | if ~stdize
|
| | 134 | IA = ismissingNumeric(A,indTmp);
|
| | 135 | else
|
| | 136 | IA = A; % Flow-through. Cannot standardize integer/logical ararys.
|
| | 137 | end
|
| | 138 | if ~AinTable && isempty(indTmp)
|
| | 139 | error(message('MATLAB:ismissing:IndicatorsIntegerLogical',class(A)));
|
| | 140 | end
|
| | 141 | else
|
| | 142 | if AinTable
|
| | 143 | % Ignore table variables of unsupported types
|
| | 144 | if ~stdize
|
| | 145 | IA = false(size(A));
|
| | 146 | else
|
| | 147 | IA = A; % Flow-through.
|
| | 148 | end
|
| | 149 | else
|
| | 150 | if iscalendarduration(A)
|
| | 151 | if ~stdize
|
| | 152 | error(message('MATLAB:ismissing:IndicatorsCalendarDuration'));
|
| | 153 | else
|
| | 154 | error(message('MATLAB:ismissing:StdizeCalendarDuration'));
|
| | 155 | end
|
| | 156 | else
|
| | 157 | error(message('MATLAB:ismissing:FirstInputInvalid'));
|
| | 158 | end
|
| | 159 | end
|
| | 160 | end
|
| | 161 | if AinTable && ~stdize
|
| | 162 | IA = collapseIntoLogicalColumn(IA);
|
| | 163 | end
|
| | 164 | end
|
| | 165 | %--------------------------------------------------------------------------
|
| | 166 | function IA = ismissingApply(A,AinTable,ind,stdize,missingValue,ismissingFun,typeid)
|
| | 167 | % Apply ismissing with indicators for arrays or table variables
|
| | 168 | if isfield(ind,typeid) || ind.hasMissingObj
|
| | 169 | % If A is an array, a cell of indicators is not supported
|
| | 170 | if ~AinTable && ind.IndIsCell && ...
|
| | 171 | (~ind.IndIsCellStr || (~iscategorical(A) && ~iscellstr(A)))
|
| | 172 | % But categorical and cellstr inputs do support cellstr indicators
|
| | 173 | error(message(['MATLAB:ismissing:Indicators',typeid]));
|
| | 174 | end
|
| | 175 | % Indicators of compatible type with A were provided
|
| | 176 | if ~stdize
|
| | 177 | % IA = ismissing(A,indicators)
|
| | 178 | if isfield(ind,typeid)
|
| | 179 | IA = ismissingFun(A,ind.(typeid));
|
| | 180 | else
|
| | 181 | IA = false(size(A));
|
| | 182 | end
|
| | 183 | if ind.hasMissingObj == 1 % empty missing obj (== 2) has no effect
|
| | 184 | IA = IA | ismissing(A);
|
| | 185 | end
|
| | 186 | else
|
| | 187 | % IA = standardizeMissing(A,indicators)
|
| | 188 | IA = A; % missing object indicators have no effect
|
| | 189 | if isfield(ind,typeid)
|
| | 190 | IA(ismissingFun(A,ind.(typeid))) = missingValue;
|
| | 191 | end
|
| | 192 | end
|
| | 193 | else
|
| | 194 | if ~AinTable
|
| | 195 | error(message(['MATLAB:ismissing:Indicators',typeid]));
|
| | 196 | end
|
| | 197 | % Flow-through for table if compatible indicators were not provided
|
| | 198 | if ~stdize
|
| | 199 | IA = false(size(A));
|
| | 200 | else
|
| | 201 | IA = A;
|
| | 202 | end
|
| | 203 | end
|
| | 204 | end
|
| | 205 | %--------------------------------------------------------------------------
|
| | 206 | function indstruct = parseIndicators(ind,AisTable,stdize)
|
| | 207 | % Parse indicators. They can be an array or a cell at this point.
|
| | 208 | indstruct = struct;
|
| | 209 | indstruct.hasMissingObj = false;
|
| | 210 | if ~iscell(ind)
|
| | 211 | indstruct.IndIsCell = false;
|
| | 212 | indstruct.IndIsCellStr = false;
|
| | 213 | indstruct = indicatorsSwitch(indstruct,ind,AisTable,stdize);
|
| | 214 | else
|
| | 215 | indstruct.IndIsCell = true;
|
| | 216 | indstruct.IndIsCellStr = iscellstr(ind);
|
| | 217 | if isempty(ind)
|
| | 218 | % {} is still a cellstr, we don't want to error for it
|
| | 219 | indstruct = addToField(indstruct,ind,'Cellstr');
|
| | 220 | indstruct = addToField(indstruct,ind,'Char');
|
| | 221 | indstruct = addToField(indstruct,ind,'Categorical');
|
| | 222 | end
|
| | 223 | for ii = 1:numel(ind)
|
| | 224 | indstruct = indicatorsSwitch(indstruct,ind{ii},AisTable,stdize);
|
| | 225 | end
|
| | 226 | end
|
| | 227 | end
|
| | 228 | %--------------------------------------------------------------------------
|
| | 229 | function indstruct = indicatorsSwitch(indstruct,ind,AisTable,stdize)
|
| | 230 | % Separate indicators according to the array type they are compatible with
|
| | 231 | if (isnumeric(ind) || islogical(ind))
|
| | 232 | ind = reshape(ind,[],1);
|
| | 233 | if isa(ind,'double')
|
| | 234 | % Double indicators supported for all numeric and logical arrays
|
| | 235 | indstruct = addToField(indstruct,{ind},'Double');
|
| | 236 | indstruct = addToField(indstruct,{ind},'Single');
|
| | 237 | indstruct = addToField(indstruct,{ind},'IntegerLogical');
|
| | 238 | elseif isa(ind,'single')
|
| | 239 | % Single indicators supported only for double and single arrays
|
| | 240 | indstruct = addToField(indstruct,{ind},'Double');
|
| | 241 | indstruct = addToField(indstruct,{ind},'Single');
|
| | 242 | else
|
| | 243 | % Integer indicators supported only for double and integer arrays
|
| | 244 | indstruct = addToField(indstruct,{ind},'Double');
|
| | 245 | indstruct = addToField(indstruct,{ind},'IntegerLogical');
|
| | 246 | end
|
| | 247 | elseif ischar(ind)
|
| | 248 | if ~isrow(ind) && ~isempty(ind)
|
| | 249 | error(message('MATLAB:ismissing:IndicatorsCharRowVector'));
|
| | 250 | end
|
| | 251 | if ~AisTable
|
| | 252 | indstruct = addToField(indstruct,ind(:),'Char');
|
| | 253 | else
|
| | 254 | % Remove trailing whitespace in indicators used for char in table
|
| | 255 | indStr = strip(matlab.internal.math.charRows2string(ind,true),'right');
|
| | 256 | indstruct = addToField(indstruct,indStr,'CharInTable');
|
| | 257 | end
|
| | 258 | % Keep whitespace in indicators used for cellstr
|
| | 259 | ind = {ind};
|
| | 260 | indstruct = addToField(indstruct,ind,'Cellstr');
|
| | 261 | % Remove leading/trailing whitespace in indicators used for categorical
|
| | 262 | indstruct = addToField(indstruct,strtrim(ind),'Categorical');
|
| | 263 | elseif isstring(ind)
|
| | 264 | ind = reshape(ind,[],1);
|
| | 265 | % Keep whitespace in indicators used for string
|
| | 266 | indstruct = addToField(indstruct,ind,'String');
|
| | 267 | % Remove <missing> string from indicators. We do not want the <missing>
|
| | 268 | % string to match up to <undefined> in a categorical.
|
| | 269 | ind(ismissing(ind)) = [];
|
| | 270 | % Remove leading/trailing whitespace in indicators for categorical, but
|
| | 271 | % don't match indicators "" and " " to <undefined>. Also, "<undefined>"
|
| | 272 | % does not match to <undefined>; only blank character vectors of any
|
| | 273 | % length, and '', and '<undefined>' match to <undefined>.
|
| | 274 | ind = deblank(ind);
|
| | 275 | ind = strip(ind);
|
| | 276 | ind(ind == "") = [];
|
| | 277 | ind(ind == string(categorical.undefLabel)) = []; % '<undefined>'
|
| | 278 | ind = reshape(ind,[],1);
|
| | 279 | indstruct = addToField(indstruct,cellstr(ind),'Categorical');
|
| | 280 | elseif isdatetime(ind)
|
| | 281 | ind = reshape(ind,[],1);
|
| | 282 | indstruct = addToField(indstruct,ind,'Datetime');
|
| | 283 | elseif isduration(ind)
|
| | 284 | ind = reshape(ind,[],1);
|
| | 285 | indstruct = addToField(indstruct,ind,'Duration');
|
| | 286 | elseif iscalendarduration(ind)
|
| | 287 | if ~stdize
|
| | 288 | error(message('MATLAB:ismissing:IndicatorsCalendarDuration'));
|
| | 289 | else
|
| | 290 | error(message('MATLAB:ismissing:StdizeCalendarDuration'));
|
| | 291 | end
|
| | 292 | elseif isa(ind,'missing')
|
| | 293 | % 1 for non-empty missing, 2 for empty missing
|
| | 294 | indstruct.hasMissingObj = 1 + isempty(ind);
|
| | 295 | else
|
| | 296 | % categorical indicators are not supported
|
| | 297 | % cellstr indicators within another cell are also not supported
|
| | 298 | error(message('MATLAB:ismissing:IndicatorsInvalidType',class(ind)));
|
| | 299 | end
|
| | 300 | end
|
| | 301 | %--------------------------------------------------------------------------
|
| | 302 | function indstruct = addToField(indstruct,ind,typeid)
|
| | 303 | % Grow the array of indicators of a certain type
|
| | 304 | if isfield(indstruct,typeid)
|
| | 305 | indstruct.(typeid) = [indstruct.(typeid); ind];
|
| | 306 | else
|
| | 307 | indstruct.(typeid) = ind;
|
| | 308 | end
|
| | 309 | end
|
| | 310 | %--------------------------------------------------------------------------
|
| | 311 | function IA = collapseIntoLogicalColumn(IA)
|
| | 312 | % Collapse 2-D and N-D table variables into one logical column
|
| | 313 | if ~iscolumn(IA)
|
| | 314 | if ~ismatrix(IA)
|
| | 315 | IA = reshape(IA,size(IA,1),[]);
|
| | 316 | end
|
| | 317 | IA = any(IA,2);
|
| | 318 | end
|
| | 319 | end
|
| | 320 | %--------------------------------------------------------------------------
|
| | 321 | function IA = ismissingNumeric(A,ind)
|
| | 322 | % A is numeric or logical, ind is numeric or logical
|
| | 323 | IA = false(size(A));
|
| | 324 | for ii = 1:numel(ind)
|
| | 325 | indii = ind{ii};
|
| | 326 | if issparse(indii)
|
| | 327 | indii = full(indii);
|
| | 328 | end
|
| | 329 | mi = isnan(indii);
|
| | 330 | if any(mi)
|
| | 331 | IA = IA | ismember(A,indii(~mi)) | isnan(A);
|
| | 332 | else
|
| | 333 | IA = IA | ismember(A,indii);
|
| | 334 | end
|
| | 335 | end
|
| | 336 | end
|
| | 337 | %--------------------------------------------------------------------------
|
| | 338 | function IA = ismissingDatetime(A,ind)
|
| | 339 | % A and ind are datetime
|
| | 340 | mi = isnat(ind);
|
| | 341 | if any(mi)
|
| | 342 | IA = ismember(A,ind(~mi)) | isnat(A);
|
| | 343 | else
|
| | 344 | IA = ismember(A,ind);
|
| | 345 | end
|
| | 346 | end
|
| | 347 | %--------------------------------------------------------------------------
|
| | 348 | function IA = ismissingDuration(A,ind)
|
| | 349 | % A and ind are duration
|
| | 350 | mi = isnan(ind);
|
| | 351 | if any(mi)
|
| | 352 | IA = ismember(A,ind(~mi)) | isnan(A);
|
| | 353 | else
|
| | 354 | IA = ismember(A,ind);
|
| | 355 | end
|
| | 356 | end
|
| | 357 | %--------------------------------------------------------------------------
|
| | 358 | function IA = ismissingCategorical(A,ind)
|
| | 359 | % A is categorical, ind is cellstr
|
| | 360 | hasUndefInd = any(cellfun('isempty',ind)) | ...
|
| | 361 | any(strcmp(categorical.undefLabel,ind));
|
| | 362 | if hasUndefInd
|
| | 363 | IA = ismember(A,ind) | isundefined(A);
|
| | 364 | else
|
| | 365 | IA = ismember(A,ind);
|
| | 366 | end
|
| | 367 | end
|
| | 368 | %--------------------------------------------------------------------------
|
| | 369 | function IA = ismissingChar(A,ind)
|
| | 370 | % A and ind are char arrays
|
| | 371 | IA = ismember(A,ind);
|
| | 372 | end
|
| | 373 | %--------------------------------------------------------------------------
|
| | 374 | function IA = ismissingCellstr(A,ind)
|
| | 375 | % A is cellstr, ind is char row vector or cellstr
|
| | 376 | IA = ismember(A,ind);
|
| | 377 | end
|
| | 378 | %--------------------------------------------------------------------------
|
| | 379 | function IA = ismissingString(A,ind)
|
| | 380 | % A and ind are string
|
| | 381 | mi = ismissing(ind);
|
| | 382 | if any(mi)
|
| | 383 | IA = ismember(A,ind(~mi)) | ismissing(A);
|
| | 384 | else
|
| | 385 | IA = ismember(A,ind);
|
| | 386 | end
|
| | 387 | end
|
< 0.001 | 2 | 388 | end % ismissingKernel
|