Errors for groupsummary() using function handles
25 次查看(过去 30 天)
显示 更早的评论
I am struggling to do a groupwise integration with groupsummary(...) using a handle to the trapz() function as the method.
Please note:
- This is about correct syntax/logic, not the numerical result.
- I am still on R2018b.
The doc.s for the current R2021a have more info for this case (which is not in R2018b), pointing out that "When the input data is a table T and you specify a function handle for method that takes more than one input argument, you must specify datavars."
R2021a also has an example but this uses the function xcov() which seems to be available only in the Signal Processing toolkit (or perhaps now in Matlab, but only after R2018b).
See the code below for (some of) the various attempts I have made, and the various resulting errors.
Using trapz() with only one argument does in fact work, but of course that way the intended array (tbA.a) is not used for the "integration steps".
It also seems that there is (or was) some ?bug with groupsummary(), but it's not clear to me if/how this has any relevance to the problem.
What am I missing?
Thanks for any pointers.
Full (non- :-)working demo example:
% set up x and y variables, column vectors for easier checking
a = [0.0:.01:0.99]' ;
b = sin(a) ;
%generate group IDs 1 ... 5, group size varies
grpID = [repmat(1,22,1);repmat(2,18,1);repmat(3,24,1);repmat(4,16,1); ...
repmat(5,20,1) ...
] ;
% create table
tbA = table(grpID,a,b,'VariableNames',{'grpID','a','b'}) ;
fh = @trapz ; %function handle for trapz(...)
%testing the handle
res1 = fh(b); % does work: res1 = 45.1306
res2 = fh(a,b); % also works: res2 = 0.4513
% integr = groupsummary(tbA,'grpID',fh(b)) ;
%ERR: Second argument, number of bins, must be a positive integer.
% [mis-parsed, see R2021a doc.s: datavars needed, and apparently even
% when function has only *one* argument]
% integr = groupsummary(tbA,'grpID',fh(b),'b') ;
%ERR: Method must be a valid name, a function handle, or a cell array
% containing valid methods.
% What's wrong with the handle here?
% integr = groupsummary(tbA,'grpID',fh(a,b),'b') ;
%ERR: Method must be a valid name, a function handle, or a cell array
% containing valid methods.
% Ditto
% integr = groupsummary(tbA,'grpID',@(x,y) trapz(x,y),{"a","b"}) ;
%ERR: Invalid data variables.
% This is the same syntax as in R2021a doc.s (see link above):
% "For example:
% groupsummary(T,groupvars,@(x,y) myFun(x,y),{"x1","y1"})
% calculates myFun(T.x1,T.y1) for each group."
integr = groupsummary(tbA,'grpID',@(x) trapz(x),'b') ;
% result: 5x3 table, integration results in integr.fun1_b
% This DOES work, but it uses trapz(...) with only *one* argument
% so is not using tbA.a for the integration steps.
0 个评论
采纳的回答
Cris LaPierre
2021-8-20
编辑:Cris LaPierre
2021-8-20
If you try to run the function handle with multiple inputs example from the R2021a doc in R2018b, you will get an error. That suggests to me the functionality needed to use groupsummary with a function handle that accepts multiple inputs did not exist in 2018b.
% set up x and y variables, column vectors for easier checking
a = [0.0:.01:0.99]' ;
b = sin(a) ;
%generate group IDs 1 ... 5, group size varies
grpID = [repmat(1,22,1);repmat(2,18,1);repmat(3,24,1);repmat(4,16,1); ...
repmat(5,20,1) ...
] ;
% create table
tbA = table(grpID,a,b) ;
G = findgroups(tbA.grpID);
C = splitapply(@trapz,tbA.a,tbA.b,G)
3 个评论
Cris LaPierre
2021-8-20
If you already have a grouping variable, you do not need to use findgroups.
% set up x and y variables, column vectors for easier checking
a = [0.0:.01:0.99]' ;
b = sin(a) ;
%generate group IDs 1 ... 5, group size varies
grpID = [repmat(1,22,1);repmat(2,18,1);repmat(3,24,1);repmat(4,16,1); ...
repmat(5,20,1) ...
] ;
% create table
tbA = table(grpID,a,b) ;
C = splitapply(@trapz,tbA.a,tbA.b,tbA.grpID)
I agree that it was unclear to me whether it was possible to use a function handle with multiple inputs in R2018b or not.
更多回答(1 个)
Dave B
2021-8-20
I think the feature of accepting multiple arguments is trying to solve this exact problem, to work around this in 18b you can pack a and b into a cell:
a = [0.0:.01:0.99]' ;
b = sin(a) ;
grpID = [repmat(1,22,1);repmat(2,18,1);repmat(3,24,1);repmat(4,16,1); ...
repmat(5,20,1) ...
] ;
tbA = table(grpID,a,b)
tbA.c = mat2cell([tbA.a tbA.b],ones(height(tbA),1),2);
integr = groupsummary(tbA,'grpID', @foo, {'c'} )
And then define foo as:
function a=foo(x)
try
xx=cell2mat(x);
a=trapz(xx(:,1),xx(:,2));
catch
a=nan;
end
end
It's a little awkward. foo might be called a couple of times outside of for your groups (set a break point to see that). I used try catch with the reasoning that - if I can't get the result it should return a NaN.
2 个评论
Dave B
2021-8-20
@Cris LaPierre's answer was better, I had forgotten that splitapply didn't have the one-arg limitation in the early releases but groupsummary did.
Hopefully features like the one that was added to groupsummary in R2020b mean that you don't have to juggle as often!
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Resizing and Reshaping Matrices 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!