Mercurial > octave
view scripts/statistics/normalize.m @ 31551:fd29c7a50a78 stable
maint: use commas, semicolons consistently with Octave conventions.
* makeValidName.m: Remove %!test and move BIST %!asserts to column 1.
* base64decode.m, base64encode.m, which.m, logm.m, uniquetol.m, perms.m:
Delete semicolon (';') at end of %!assert BIST.
* lin2mu.m, interp2.m, interpn.m, lsqnonneg.m, pqpnonneg.m, uniquetol.m,
betainc.m, normalize.m: Add semicolon (';') to end of assert statement within
%!test BIST.
* __memoize__.m, tar_is_bsd.m, publish.m: Add semicolon (';') to line with
keyword "persistent".
* stft.m: Use comma (',') after "case" keyword when code immediately follows.
* gallery.m: Align commas used in case statements in massive switch block.
Remove unnecessary parentheses around a numeric case argument.
* ranks.m: Remove semicolon (';') from case statemnt argument.
author | Rik <rik@octave.org> |
---|---|
date | Sat, 26 Nov 2022 06:32:08 -0800 |
parents | 84fa33608593 |
children | 597f3ee61a48 |
line wrap: on
line source
######################################################################## ## ## Copyright (C) 2017-2022 The Octave Project Developers ## ## See the file COPYRIGHT.md in the top-level directory of this ## distribution or <https://octave.org/copyright/>. ## ## This file is part of Octave. ## ## Octave is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## Octave is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## <https://www.gnu.org/licenses/>. ## ######################################################################## ## -*- texinfo -*- ## @deftypefn {} {@var{z} =} normalize (@var{x}) ## @deftypefnx {} {@var{z} =} normalize (@var{x}, @var{dim}) ## @deftypefnx {} {@var{z} =} normalize (@dots{}, @var{method}) ## @deftypefnx {} {@var{z} =} normalize (@dots{}, @var{method}, @var{option}) ## @deftypefnx {} {@var{z} =} normalize (@dots{}, @var{scale}, @var{scaleoption}, @var{center}, @var{centeroption}) ## @deftypefnx {} {[@var{z}, @var{c}, @var{s}] =} normalize (@dots{}) ## ## Return a normalization of the data in @var{x} using one of several available ## scaling and centering methods. ## ## @code{normalize} by default will return the @code{zscore} of @var{x}, ## defined as the number of standard deviations each element is from the mean ## of @var{x}. This is equivalent to centering at the mean of the data and ## scaling by the standard deviation. ## ## The returned value @var{z} will have the same size as @var{x}. The optional ## return variables @var{c} and @var{s} are the centering and scaling factors ## used in the normalization such that: ## ## @example ## @group ## @tcode{@var{z} = (@var{x} - @var{c}) ./ @var{s}} ## @end group ## @end example ## ## If @var{x} is a vector, @code{normalize} will operate on the data in ## @var{x}. ## ## If @var{x} is a matrix, @code{normalize} will operate independently on ## each column in @var{x}. ## ## If @var{x} is an N-dimensional array, @code{normalize} will operate ## independently on the first non-singleton dimension in @var{x}. ## ## If the optional second argument @var{dim} is given, operate along this ## dimension. ## ## The optional inputs @var{method} and @var{option} can be used to specify the ## type of normalization performed on @var{x}. Note that only the ## @option{scale} and @option{center} options may be specified together using ## any of the methods defined below. Valid normalization methods are: ## ## @table @code ## @item zscore ## (Default) Normalizes the elements in @var{x} to the scaled distance from a ## central value. Valid Options: ## ## @table @code ## @item std ## (Default) Data is centered at @code{mean (@var{x})} and scaled by the ## standard deviation. ## ## @item robust ## Data is centered at @code{median (@var{x})} and scaled by the median ## absolute deviation. ## @end table ## ## @item norm ## @var{z} is the general vector norm of @var{x}, with @var{option} being the ## normalization factor @var{p} that determines the vector norm type according ## to: ## @tex ## $$Z = \left (\sum_k \left | X_k \right |^P \right )^{1/P}$$ ## @end tex ## @ifnottex ## ## @example ## @group ## @tcode{@var{z} = [sum (abs (@var{x}) .^ @var{p})] ^ (1/@var{p})} ## @end group ## @end example ## ## @end ifnottex ## @var{p} can be any positive scalar, specific values being: ## ## @table @code ## @item @var{p} = 1 ## @var{x} is normalized by @code{sum (abs (@var{x}))}. ## ## @item @var{p} = 2 ## (Default) @var{x} is normalized by the Euclidian norm, or vector ## magnitude, of the elements. ## ## @item @var{P} = Inf ## @var{x} is normalized by @code{max (abs (@var{x}))}. ## @end table ## ## @item scale ## @var{x} is scaled by a factor determined by @var{option}, which can be a ## numeric scalar or one of the following: ## ## @table @code ## @item std ## (Default) @var{x} is scaled by its standard deviation. ## ## @item mad ## @var{x} is scaled by its median absolute deviation. ## ## @item first ## @var{x} is scaled by its first element. ## ## @item iqr ## @var{x} is scaled by its interquartile range. ## @end table ## ## @item range ## @var{x} is scaled to fit the range specified by @var{option} as a two ## element scalar row vector. The default range is [0, 1]. ## ## @item center ## @var{x} is shifted by an amount determined by @var{option}, which can be a ## numeric scalar or one of the following: ## ## @table @code ## @item mean ## (Default) @var{x} is shifted by @code{mean (@var{x})}. ## ## @item median ## @var{x} is shifted by @code{median (@var{x})}. ## @end table ## ## @item medianiqr ## @var{x} is shifted by @code{median (@var{x})} and scaled by the ## interquartile range. ## @end table ## ## Known @sc{matlab} incompatibilities: ## ## @enumerate ## @item ## The option @option{DataVariables} is not yet implemented for Table class ## @var{x} inputs. ## ## @item ## Certain arrays containing NaN elements may not return @sc{matlab} compatible ## output. ## @end enumerate ## ## @seealso{zscore, iqr, norm, rescale, std, median, mean, mad} ## @end deftypefn function [z, c, s] = normalize (x, varargin) ## FIXME: Until NANFLAG/OMITNAN option is implemented in std, mean, median, ## etc., normalize cannot efficiently reproduce some behavior with NaNs in ## x. xtests added to capture this. (See bug #50571) ## FIXME: When table class is implemented, remove DataVariables error line in ## option checking section and add DataVariables data handling switch ## section. ## Input validation if (nargin < 1 || nargin > 8) print_usage (); endif if (! isnumeric (x)) error ("normalize: X must be a numeric vector, matrix, or array"); endif if (nargin == 1) ## Directly handle simple 1 input case. [s, c] = std (x); else ## Parse input options dim = []; method = []; methodoption = []; datavariables_flag = false; datavar = []; scale_and_center_flag = false; vararg_idx = 1; ## Only second optional input can be numeric without following a method. if (isnumeric (varargin{1})) dim = varargin{1}; ## Check for valid dimensions if (! (isscalar (dim) && dim == fix (dim) && dim > 0)) error ("normalize: DIM must be an integer and a valid dimension"); endif vararg_idx++; endif ## Parse varargin to determine methods then options. n_varargin = nargin - 1; while (vararg_idx <= n_varargin) ## Arguments after second cannot be numeric without following a method. if (isnumeric (varargin{vararg_idx})) print_usage (); endif prop = tolower (varargin{vararg_idx}); if (strcmp (prop, "datavariables")) ## FIXME: Remove error on next line and undo block comment when support ## for Tables is implemented. error ("normalize: DataVariables method not yet implemented"); #{ if (vararg_idx == n_varargin) error (["normalize: DataVariables requires a table variable", ... " be specified"]); elseif (datavariables_flag == true) error ("normalize: DataVariables may only be specified once"); else datavariables_flag = true; datavar = varargin{vararg_idx+1}; vararg_idx++; endif #} else if (! isempty (method)) ## Catch if a second method is passed if (scale_and_center_flag) ## if true, already specified two methods, three never possible error ("normalize: more than two methods specified"); elseif (strcmp ({method, prop}, {"center", "scale"}) || strcmp ({method, prop}, {"scale", "center"})) ## Only scale and center can be called together scale_and_center_flag = true; ## scale/center order doesn't matter, avoid overwriting first one stored_method = method; method = []; stored_methodoption = methodoption; methodoption = []; else ## not scale and center, throw appropriate error if (any (strcmp (prop, {"zscore", "norm", "range", "scale", ... "center", "medianiqr"}))) error ("normalize: methods '%s' and '%s' may not be combined", method, prop); else error ("normalize: unknown method '%s'", prop); endif endif endif ## Determine method and whether there's an appropriate option specified switch (prop) case "zscore" method = "zscore"; if (vararg_idx < n_varargin) nextprop = tolower (varargin{vararg_idx+1}); if (strcmp (nextprop, "std") || strcmp (nextprop, "robust")) methodoption = nextprop; vararg_idx++; endif endif if (isempty (methodoption)) methodoption = "std"; endif case "norm" method = "norm"; if (vararg_idx < n_varargin && isnumeric (varargin{vararg_idx+1})) nextprop = varargin{vararg_idx+1}; if (isscalar (nextprop) && (nextprop > 0)) methodoption = nextprop; vararg_idx++; else error (["normalize: 'norm' option must be a positive ", ... "scalar or Inf"]); endif endif if (isempty (methodoption)) methodoption = 2; endif case "range" method = "range"; if (vararg_idx < n_varargin && isnumeric (varargin{vararg_idx+1})) nextprop = varargin{vararg_idx+1}; if (any (size (nextprop) != [1 2])) error (["normalize: 'range' must be specified as a ", ... "2-element row vector [a, b]"]); endif methodoption = nextprop; vararg_idx++; endif if (isempty (methodoption)) methodoption = [0, 1]; endif case "scale" method = "scale"; if (vararg_idx < n_varargin) nextprop = tolower (varargin{vararg_idx+1}); if (isnumeric (nextprop)) if (! isscalar (nextprop)) error ("normalize: scale value must be a scalar"); else methodoption = nextprop; vararg_idx++; endif elseif (any (strcmp (nextprop, {"std", "mad", "first", "iqr"}))) methodoption = nextprop; vararg_idx++; endif endif if (isempty (methodoption)) methodoption = 'std'; endif case "center" method = "center"; if (vararg_idx < n_varargin) nextprop = tolower (varargin{vararg_idx+1}); if (isscalar (nextprop) || any (strcmp (nextprop, {"mean", "median"}))) methodoption = nextprop; vararg_idx++; elseif (isnumeric (nextprop)) error ("normalize: center shift must be a scalar value"); endif endif if (isempty (methodoption)) methodoption = 'mean'; endif case "medianiqr" method = "medianiqr"; otherwise error ("normalize: unknown method '%s'", prop); endswitch endif vararg_idx++; endwhile if (scale_and_center_flag) method = "scaleandcenter"; endif if (isempty (method)) method = 'zscore'; methodoption = 'std'; endif if (isempty (dim)) ## Operate on first non-singleton dimension. (dim = find (size (x) > 1, 1)) || (dim = 1); endif ## Perform normalization based on specified methods ## FIXME: DataTables option not handled below. Fix after Table Class ## has been implemented. ## Default center/scale factors: c = 0; s = 1; switch (method) case "zscore" switch (methodoption) case "std" [s, c] = std (x, [], dim); case "robust" ## center/median to zero and MAD = 1 c = median (x, dim); ## FIXME: Use bsxfun, rather than broadcasting, until broadcasting ## supports diagonal and sparse matrices (Bugs #41441, #35787). s = median (abs (bsxfun (@minus, x , c)), dim); ## s = median (abs (x - c), dim); # Automatic broadcasting endswitch case "norm" switch (methodoption) case 1 s = sum (abs (x), dim); case Inf s = max (abs (x), [], dim); otherwise s = sum (abs (x) .^ methodoption, dim) .^ (1/methodoption); endswitch case "range" ## if any range element = 0, avoid divide by zero by replacing that ## range element with 1. output will be zero+min due to x-min(x)=0. x_range = range (x, dim); x_range(x_range == 0) = 1; z_range = methodoption(2) - methodoption(1); s = x_range ./ z_range; c = min (x, [], dim) - (methodoption(1) .* s); case "scale" s = process_scale_option (x, dim, methodoption); case "center" c = process_center_option (x, dim, methodoption); case "scaleandcenter" ## repeats scale and center using appropriate order and info switch (stored_method) case "scale" ## stored info is scale, latest info is center center_option = methodoption; scale_option = stored_methodoption; case "center" ## stored info is center, latest info is scale center_option = stored_methodoption; scale_option = methodoption; endswitch s = process_scale_option (x, dim, scale_option); c = process_center_option (x, dim, center_option); case "medianiqr" c = median (x, dim); s = iqr (x, dim); endswitch endif ## Divide by scale factor. If scale = 0, divide by zero = Inf, which is OK. ## FIXME: Use bsxfun, rather than broadcasting, until broadcasting ## supports diagonal and sparse matrices (Bugs #41441, #35787). z = bsxfun (@rdivide, bsxfun (@minus, x , c), s); ## z = (x - c) ./ s; # Automatic broadcasting endfunction function c = process_center_option (x, dim, center_option) if (isnumeric (center_option)) c = center_option; else switch (center_option) case "mean" c = mean (x, dim); case "median" c = median (x, dim); endswitch endif endfunction function s = process_scale_option (x, dim, scale_option) warning ("off", "Octave:divide-by-zero", "local"); if (isnumeric (scale_option)) s = scale_option; else switch (scale_option) case "std" s = std (x, [], dim); case "mad" s = mad (x, 1, dim); case "first" dim_vector = repmat ({':'}, ndims(x), 1); dim_vector{dim} = 1; s = x(dim_vector{:}); case "iqr" s = iqr (x, dim); endswitch endif endfunction ## no method specified, using zscore & std %!assert (normalize ([1,2,3]), [-1,0,1]) %!assert (normalize ([1,2,3], 2), [-1,0,1]) %!assert (normalize (single ([1,2,3])), single ([-1,0,1])) %!assert (normalize ([2,0,-2;0,2,0;-2,-2,2]), [1,0,-1;0,1,0;-1,-1,1]) %!assert (normalize (magic (3)), [[3;-2;-1]/sqrt(7),[-1;0;1],[1;2;-3]/sqrt(7)]) %!assert (normalize (magic (3), 2), [[3 -4 1]/sqrt(13);[-1 0 1];[-1 4 -3]/sqrt(13)]) ## Method: zscore, [std, robust] %!assert (normalize ([1,2,3],"zscore","std"), [-1,0,1]) %!assert (normalize ([2,0,-2;0,2,0;-2,-2,2],"zscore","std"), [1,0,-1;0,1,0;-1,-1,1]) %!assert (normalize (magic (3),"zscore","std"), [[3;-2;-1]/sqrt(7),[-1;0;1],[1;2;-3]/sqrt(7)]) %!assert (normalize ([1,2,3],"zscore","robust"), [-1,0,1]) %!assert (normalize ([2,0,-2;0,2,0;-2,-2,2],"zscore","robust"), [1,0,-1;0,1,0;-1,-1,1]) %!assert (normalize (magic (3),"zscore","robust"), [4 -1 0; -1 0 1; 0 1 -4]) ## Method: norm [1, 2, inf] %!assert (normalize ([1,2,3],"norm",1), [1/6 1/3 1/2]) %!assert (normalize ([2,0,-2;0,2,0;-2,-2,2],"norm",1), [1,0,-1;0,1,0;-1,-1,1]/2) %!assert (normalize (magic (3),"norm",1), magic(3)/15) %!assert (normalize ([1,2,3],"norm",2), [1 2 3]./3.741657386773941, eps) %!assert (normalize ([2,0,-2;0,2,0;-2,-2,2],"norm",2), [1,0,-1;0,1,0;-1,-1,1]*(sqrt(2)/2), eps) %!assert (normalize ([1,2,3],"norm",Inf), [1/3 2/3 1]) %!assert (normalize ([2,0,-2;0,2,0;-2,-2,2],"norm",Inf), [1,0,-1;0,1,0;-1,-1,1]) %!assert (normalize (magic (3),"norm",Inf), [[8;3;4]/8,[1;5;9]/9,[6;7;2]/7]) ## Method: range %!assert (normalize ([1,2,3],"range"), [0 0.5 1]) %!assert (normalize ([2,0,-2;0,2,0;-2,-2,2],"range",[0 1]), [1,0.5,0;0.5,1,0.5;0,0,1]) %!assert (normalize (magic (3),"range",[-1 1]), [1 -1 0.6; -1 0 1; -0.6 1 -1], eps) ## Method: scale [mad first iqr number] %!assert (normalize ([1,2,3],"scale"), [1 2 3]) %!assert (normalize ([2,0,-2;0,2,0;-2,-2,2],"scale","std"), [1 0 -1; 0 1 0; -1 -1 1]) %!assert (normalize (magic (3),"scale",2), (magic(3)/2)) %!assert (normalize ([1,2,3],"scale", "mad"), [1 2 3]) %!assert (normalize ([2,0,-2;0,2,0;-2,-2,2],"scale","mad"), [1 0 -1; 0 1 0; -1 -1 1]) %!assert (normalize (magic (3),"scale","mad"), [8 0.25 6; 3 1.25 7; 4 2.25 2]) %!assert (normalize ([1,2,3],"scale", "first"), [1 2 3]) %!assert (normalize ([2,0,-2;0,2,0;-2,-2,2],"scale","first"), [1 NaN 1; 0 Inf 0; -1 -Inf -1]) %!assert (normalize (magic (3),"scale","first"), [1 1 1; 3/8 5 7/6; 0.5 9 1/3]) %!assert (normalize (magic (3),2,"scale","first"), [1 1/8 3/4;1 5/3 7/3;1 9/4 0.5]) %!test %! x = reshape (magic (4),2,2,2,2); %! y3 = cat (4, cat (3,ones(2),[1/8 7/9;11/5 7/2]), cat (3,ones(2),[13/3 2; 4/5 1/15])); %! y4 = cat (4, ones (2,2,2), cat (3,[3/16 2/3; 2 15/4],[6.5 12/7; 8/11 1/14] )); %! assert (normalize (x, 3, "scale", "first"), y3); %! assert (normalize (x, 4, "scale", "first"), y4); %!assert (normalize ([1,2,3], "scale", "iqr"), [1 2 3]*2/3) %!assert (normalize ([1,2,3]', "scale", "iqr"), ([1 2 3]')*2/3) %!assert (normalize ([2,0,-2;0,2,0;-2,-2,2],"scale","iqr"), [1 0 -1; 0 1 0; -1 -1 1]* 2/3, eps) %!assert (normalize (magic (3),"scale","iqr"), [[8;3;4]/3.75,[1;5;9]/6,[6;7;2]/3.75],eps) ## Method: center [mean median number] %!assert (normalize ([1,2,3], "center"), [-1 0 1]) %!assert (normalize ([1,2,3], 1, "center"), [0 0 0]) %!assert (normalize ([1,2,3], "center", 10), [-9 -8 -7]) %!assert (normalize ([1 2 3 10], "center", "mean"), [-3 -2 -1 6]) %!assert (normalize ([1 2 3 10], "center", "median"), [-1.5 -0.5 0.5 7.5]) ## Method: medianiqr %!assert (normalize ([1,2,3], "medianiqr"), [-1 0 1]*2/3) %!assert (normalize ([1,2,3]', "medianiqr"), ([-1 0 1]')*2/3) %!assert (normalize ([2,0,-2;0,2,0;-2,-2,2], "medianiqr"), [1 0 -1; 0 1 0; -1 -1 1]*2/3) %!assert (normalize (magic (3), "medianiqr"), [8/5 -1 0; -2/5 0 2/5; 0 1 -8/5]*2/3) ## Test NaN and Inf %!assert (normalize ([1 2 Inf], 2), [NaN, NaN, NaN]) %!assert (normalize ([1 2 3], 1), [NaN, NaN, NaN]) %!assert (normalize ([1 2 3], 3), [NaN, NaN, NaN]) %!assert (normalize (ones (3,2,2,2)), NaN (3,2,2,2)) %!assert (normalize (Inf), NaN) %!assert (normalize (NaN), NaN) %!assert (normalize ([Inf, NaN]), [NaN, NaN]) %!assert (normalize ([Inf, NaN]'), [NaN, NaN]') %!assert (normalize ([Inf, Inf], 1), [NaN, NaN]) %!assert (normalize ([Inf, Inf], 2), [NaN, NaN]) %!assert (normalize ([Inf, Inf]', 1), [NaN, NaN]') %!assert (normalize ([Inf, Inf]', 2), [NaN, NaN]') %!assert (normalize ([1 2 NaN; NaN 3 4], 1), [NaN -1 NaN; NaN 1 NaN]*sqrt(2)/2, eps) ## Two input methods, must be scale and center %!assert (normalize (magic(3), "scale", "center"), normalize (magic(3), "zscore"), eps) %!assert (normalize (magic(3), "center", "scale"), normalize (magic(3), "zscore"), eps) ## Test additional outputs %!test %! [z, c, s] = normalize ([1, 2, 3], 2); %! assert ({z, c, s}, {[-1 0 1], [2], [1]}); %! [z, c, s] = normalize (magic (3), "zscore", "std"); %! assert ({z, c, s}, {[[3;-2;-1]/sqrt(7),[-1;0;1],[1;2;-3]/sqrt(7)], [5 5 5], [sqrt(7) 4 sqrt(7)]}); %! [z, c, s] = normalize (magic (3), "zscore", "robust"); %! assert ({z, c, s}, {[4 -1 0; -1 0 1; 0 1 -4], [4 5 6], [1 4 1]}); %! [z, c, s] = normalize (magic (3), "norm", 1); %! assert ({z, c, s}, {magic(3)/15 , 0, [15 15 15]}); %! [z, c, s] = normalize ([2,0,-2;0,2,0;-2,-2,2],"norm",2); %! assert ({z, c, s}, {[1,0,-1;0,1,0;-1,-1,1]*(sqrt(2)/2), 0, [1 1 1]*2*sqrt(2)}, eps); %! [z, c, s] = normalize ([1 2 3], "norm", Inf); %! assert ({z, c, s}, {[1 2 3]/3, 0, 3}, eps); %! [z, c, s] = normalize (magic (3),"range",[-1 1]); %! assert ({z, c, s}, {[1 -1 0.6; -1 0 1; -0.6 1 -1], [5.5 5 4.5], [2.5 4 2.5]}, eps); %! [z, c, s] = normalize (magic (3),"scale","mad"); %! assert ({z, c, s}, {[8 0.25 6; 3 1.25 7; 4 2.25 2], 0, [1 4 1]}); %! [z, c, s] = normalize (magic (3),"scale","first"); %! assert ({z, c, s}, {[1 1 1; 3/8 5 7/6; 0.5 9 1/3],0, [8 1 6]}, eps); %! [z, c, s] = normalize ([1,2,3]', "scale", "iqr"); %! assert ({z, c, s}, {([1 2 3]')*2/3, 0, 1.5}); %! [z, c, s] = normalize ([1,2,3], "center", 10); %! assert ({z, c, s}, {[-9 -8 -7], 10, 1}); %! [z, c, s] = normalize ([1 2 3 10], "center", "mean"); %! assert ({z, c, s}, {[-3 -2 -1 6], 4, 1}); %! [z, c, s] = normalize ([1 2 3 10], "center", "median"); %! assert ({z, c, s}, {[-1.5 -0.5 0.5 7.5], 2.5, 1}); %! [z, c, s] = normalize (magic (3), "medianiqr"); %! assert ({z, c, s}, {[8/5 -1 0; -2/5 0 2/5; 0 1 -8/5]*2/3, [4 5 6], [3.75 6 3.75]}, eps); %! [z, c, s] = normalize ([1 2 Inf], 2); %! assert ({z, c, s}, {[NaN, NaN, NaN], Inf, NaN}); %! [z, c, s] = normalize (Inf); %! assert ({z, c, s}, {NaN, Inf, NaN}); ## Test sparse and diagonal inputs %!test %! [z, c, s] = normalize (eye (2)); %! assert (z, (sqrt(2)/2)*[1, -1; -1, 1], eps); %! assert (c, [0.5, 0.5], eps); %! assert (s, (sqrt(2)/2)*[1, 1], eps); %!test %! [z, c, s] = normalize (sparse (eye (2))); %! assert (full (z), (sqrt(2)/2)*[1, -1; -1, 1], eps); %! assert (full (c), [0.5, 0.5], eps); %! assert (full (s), (sqrt(2)/2)*[1, 1], eps); %!test %! [z, c, s] = normalize (sparse (magic (3)), "zscore", "robust"); %! assert (full (z), [4 -1 0; -1 0 1; 0 1 -4], eps); %! assert (full (c), [4, 5, 6], eps); %! assert (full (s), [1, 4, 1], eps); %!test <55765> %! [z, c, s] = normalize (sparse (eye(2))); %! assert (issparse (z)); %! assert (issparse (c)); %! assert (issparse (s)); %!test <55765> %! [z, c, s] = normalize (sparse (magic (3)), "zscore", "robust"); %! assert (issparse (z)); %! assert (issparse (c)); %! assert (issparse (s)); ## Matlab ignores NaNs, operating as if the vector had one less element, then ## returns the result retaining the NaN in the solution. %!assert <50571> (normalize ([1 2 NaN], 2), [-1, 1, NaN]*sqrt(2)/2) %!assert <50571> (normalize ([1 2 NaN; 1 2 3], 2), [[-1 1 NaN]*sqrt(2)/2; -1 0 1], eps) ## Test input validation %!error <Invalid call> normalize () %!error <Invalid call> normalize (1, 2, 3) %!error <X must be a numeric> normalize (['A'; 'B']) %!error <DIM must be an integer> normalize (1, ones (2,2)) %!error <DIM must be an integer> normalize (1, 1.5) %!error <DIM must be .* a valid dimension> normalize (1, 0) %!error <more than two methods specified> normalize ([1 2 3], "scale", "center", "norm") %!error <methods .* may not be combined> normalize ([1 2 3], "norm", "zscore") %!error <unknown method 'foo'> normalize ([1 2 3], "norm", "foo") % %!error <'norm' option must be a positive scalar or Inf> normalize ([1 2 3], "norm", [1 2]) %!error <'norm' option must be a positive scalar or Inf> normalize ([1 2 3], "norm", -1) %!error <'range' must be specified as> normalize ([1 2 3], "range", [1 2]') %!error <'range' must be specified as> normalize ([1 2 3], "range", [1 2 3]) %!error <'range' must be specified as> normalize ([1 2 3], "range", 1) %!error <scale value must be a scalar> normalize ([1 2 3], "scale", [1 2 3]) %!error <center shift must be a scalar value> normalize ([1 2 3], "center", [1 2]) %!error <unknown method 'foo'> normalize ([1 2 3], "foo")