使用feval调用函数时,MATLAB“输出参数过多”错误

kyks70gy  于 2023-03-03  发布在  Matlab
关注(0)|答案(1)|浏览(526)

我意识到使用feval动态调用函数效率很低,但在我的应用程序中它非常方便,而且运行良好,除了一个函数的情况。我只是不知道是什么原因导致了这个问题。这个函数在以通常的方式调用时运行良好,但在使用feval调用时会引发错误(下面的最后一行):

x = 200;
[y_mean, y_sigma, y_int] = lin_model_predict(model, x, vars, params);  % works fine

assert(round(y_mean, 4) == 139.7200);
assert(isequaln(y_sigma, nan));
assert(isequal(round(y_int, 4), [137.5938  141.8462]));

% Test again using feval
f_name = "lin_model_predict";  % this will later be set programatically
[y_mean, y_sigma, y_int] = feval(f_name, model, x, vars, params);  % raises error

我包括以下函数代码供参考:

function [y_mean, y_sigma, y_int] = lin_model_predict(model, x, vars, ...
    params)
% [y_mean, y_sigma, x_int] = lin_model_predict(model, x, vars, params)
% Make predictions with a linear model of the form:
%
%   power = a + b * load 
%

    % Make predictions using model
    [y_mean, y_int] = predict(model, x, 'Alpha', vars.significance);

    % TODO: Is there a need for sigma estimates?
    y_sigma = nan(size(x));

end

完整错误消息:

Error using classreg.regr/CompactPredictor/feval
Too many output arguments.

Error in test_lin_models (line 46)
[y_mean, y_sigma, y_int] = feval(f_name, model, x, vars, params);

Matlab版本:小行星2021

更新

将最后一行替换为:

a = feval(f_name, model, x, vars, params);

我发现它需要一个输出参数。
通过调试这个调用,我发现它调用的是CompactPredictor.m中某个类的方法,位置如下:
/应用程序/MATLAB_R2021b.app/工具箱/统计信息/类规则/+类规则/+规则/紧凑型预测器.m
从该函数的文档字符串中:

function yPred = feval(model,varargin)
%FEVAL Evaluate model as a function
%    YPRED = FEVAL(M,X1,X2,...Xp) computes an array YPRED of predicted
%    values from the regression model M using predictor values X1, X2, ...,
%    Xp, where P is the number of predictors in M.  Each X argument must be
%    the same size, and must have the same type as the corresponding
%    predictor variable. The size of the YPRED output is the same as the
%    common size of the X inputs.

在本例中,模型参数现在是字符串"lin_model_predict",这将引发新的错误Unrecognized method, property, or field 'NumPredictors' for class 'string'.
所以在我看来feval的标准用法已经被这个类方法劫持了。
不知道该怎么避免,有什么想法吗?
我决定在Mathworks论坛上发布这个问题,因为它可能需要Maven的投入:

请随意在此处或此处添加答案。

gdrx4gfi

gdrx4gfi1#

在你这行

[y_mean, y_sigma, y_int] = feval(f_name, model, x, vars, params);

其中一个参数是CompactPredictor类(可能是model?),它触发了feval的重载版本被调用。这就是MATLAB如何进行重载解析的。
有几种方法可以解决这个问题,一种是不使用这个类的对象,可以写lin_model_predict来获取一个单元格数组作为输入,这样你就可以用lin_model_predict({model, x, vars, params})来调用它;另一种是使用builtin

[y_mean, y_sigma, y_int] = builtin('feval', f_name, model, x, vars, params);

第三种解决方案是不使用feval,而是编写一个函数来调用正确的函数:

function [y_mean, y_sigma, y_int] = my_feval(function_name, varargin)
switch function_name
  case 'lin_model_predict':
    [y_mean, y_sigma, y_int] = lin_model_predict(varargin{:});
  case 'other_function':
    [y_mean, y_sigma, y_int] = other_function(varargin{:});
  otherwise:
    error(['Unknown function ', function_name])
end

正如用户horchler在评论中所写的,函数句柄是一种比字符串更简洁的引用函数的方式,使用函数句柄可以:

f_handle = @lin_model_predict; % instead of f_name = "lin_model_predict";
[y_mean, y_sigma, y_int] = f_handle(model, x, vars, params);

但在某些情况下,只有字符串才有意义:可能被引用的函数是私有函数,您不希望调用者直接访问它们;或者字符串来自GUI或配置文件中的下拉菜单。在这些情况下,您可以使用表查找将字符串转换为函数句柄,请参见containers.Mapdictionary(自R2022 b起)。

相关问题