Using one variable containing all name-value pairs for built-in Matlab functions

31 views (last 30 days)
I want to give users of my code the option to specify name-value pairs when/if they care about them, but if they don't specify them, let Matlab use default values.
For example, a user might enter an options structure for an SVM classifier such as:
Options.kernel = 'rbf';
Options.kernelScale = 0.15;
Then my program would train an SVM classifier using these parameters:
svmModel = fitcsvm(observations, labels, 'KernelFunction', Options.kernel, 'KernelScale', Options.kernelScale)
But if the user only enters the options structure with the 'kernel' field, then my program would call
svmModel = fitcsvm(observations, labels, 'KernelFunction', Options.kernel)
leaving the kernel scale as the default. The issue comes down to how to do this elegantly. I can check all the field names of the Options structure, looking for name value pairs to assign, e.g.
if any(strcmp('kernel', fieldnames(Options)))
if strcmp('rbf', Options.kernel) && any(strcmp('kernelScale', fieldnames(Options)))
svmModel = fitcsvm(observations, labels, 'KernelFunction', Options.kernel, 'KernelScale', Options.kernelScale);
else
svmModel = fitcsvm(observations. labels, 'KernelFunction', Options.kernel);
end
end
But this can quickly get unwieldy for built-in functions with lots of options. Is there a better way? What I'd like to do is send in a single variable with all the name-value pairs, but when I do this, Matlab interprets varargin as being one value not a set of name-value pairs, e.g.
% Set up parameters for model
nameValuePairs = {'KernelFunction', Options.kernel};
switch Options.kernel
case {'rbf', 'gaussian'}
if any(strcmp('kernelScale', fieldnames(Options)))
nameValuePairs = cat(2, nameValuePairs, ...
{'KernelScale', Options.kernelScale});
end
case {'polynomial'}
if any(strcmp('polynomialOrder', fieldnames(Options)))
nameValuePairs = cat(2, nameValuePairs, ...
{'PolynomialOrder', Options.polynomialOrder});
end
end
% Train
svmModel = fitcsvm(observations, labels, nameValuePairs);
Is there a way to make Matlab interpret a single variable as a set of name-value pairs? Many thanks for any thoughts on this!

Accepted Answer

Matt J
Matt J on 2 Dec 2019
Edited: Matt J on 2 Dec 2019
See inputParser
which by default will expand structures into Name-Value pairs for you automatically. Note, however, that you have the option of turning this behavior off,
  3 Comments
Matt J
Matt J on 2 Dec 2019
Edited: Matt J on 2 Dec 2019
addOptional isn't what you want. You need to use addParameter.
addParameter(p, 'Kernel', 'linear');
addParameter(p, 'KernelScale', 1);
To pass the parsed name-value pairs to another function, you can use my attached struct2pairs mfunction,
parse(p, Options);
nvPairs=struct2pairs(p.Results);
svmModel = fitcsvm(observations, labels, nvPairs{:});
Sandy Throckmorton
Sandy Throckmorton on 3 Dec 2019
Thanks, Matt J! From working through your code, I can see the only thing I was doing wrong before was not transposing my cell array. But the solution you give is also much much cleaner than what I was doing. Many thanks!

Sign in to comment.

More Answers (1)

Image Analyst
Image Analyst on 2 Dec 2019
If you have version 2019b or later version of MATLAB, you might want to use the arguments block.
See Loren's latest blog to learn how it replaces the old input parser.
For example:
arguments % R2019b or newer
Tpoints(1, :) double {mustBeNumeric, mustBeNonnegative} = 0:0.1:10
beta(1, 1) double {mustBeReal} = 3.4e-5
c(1, 1) double {mustBeReal} = 3.3
delta(1, 1) double {mustBeReal} = 3.4
p(1, 1) double {mustBeReal} = 7.9e-3
end
The variable names at the beginning of those lines above are the variables passed into your function via the arguments list. Use whatever names you have for your particular function.
  1 Comment
Matt J
Matt J on 2 Dec 2019
Edited: Matt J on 2 Dec 2019
Sadly, the new arguments block functionality does not seem to have the StructExpand functionality that inputParser does (no idea why - it seems like it should be easy). Example,
s.a=3;
s.b=5;
ab0=local
ab1=local('a',3,'b',5)
ab2=local(s)
function ab=local(options)
arguments
options.a=1;
options.b=2;
end
ab=[options.a,options.b];
end
results in
ab0 =
1 2
ab1 =
3 5
Error using test>local
Invalid input argument list. Too many input arguments.
If specifying name-value arguments, ensure that all required inputs are provided, and check for
invalid name.
Error in test (line 6)
ab2=local(s)

Sign in to comment.

Categories

Find more on Argument Definitions 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!