Errors for groupsummary() using function handles
23 views (last 30 days)
Show older comments
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 Comments
Accepted Answer
Cris LaPierre
on 20 Aug 2021
Edited: Cris LaPierre
on 20 Aug 2021
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 Comments
Cris LaPierre
on 20 Aug 2021
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.
More Answers (1)
Dave B
on 20 Aug 2021
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 Comments
Dave B
on 20 Aug 2021
@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!
See Also
Categories
Find more on Resizing and Reshaping Matrices 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!