MATLAB: return both arguments from ISMEMBER when used inside SPLITAPPLY

Viewed 257

How can I access both arguments of ismember when it is used inside splitapply?

slitapply only returns scalar values for each group, so in order to compute nonscalar values for each group (as returned by the first argument of ismemebr), one has to enclose the anonymous function (in this case ismember) inside curly brackets {} to return a cell array.

But now, when I provide two output arguments to splitapply, I get an error:

Output argument "varargout{2}" (and maybe others) not assigned during call to "@(x,y) {ismember(x,y)}"

ADD 1

I can create another function, say, ismember2cell which would apply ismember and turn outputs into cell arrays:

function [a, b] = ismember2cell(x,y)
  [a,b] = ismember(x,y);
  a = {a};
  b = {b};
end

but maybe there is a solution which doesn't require this workaround.

2 Answers

One potentially faster option is to just do what splitapply is already doing under the hood by splitting your data into cell arrays (using functions like mat2cell or accumarray) and then using cellfun to apply your function across them. Using cellfun will allow you to easily capture multiple outputs (such as from ismember). For example:

% Sample data:
A = [1 2 3 4 5];
B = [1 2 1 5 5];
G = [1 1 1 2 2];  % Group index

% Group data into cell arrays:
cellA = accumarray(G(:), A(:), [], @(x) {x(:).'});  % See note below about (:).' syntax
cellB = accumarray(G(:), B(:), [], @(x) {x(:).'});

% Apply function:
[Lia, Locb] = cellfun(@ismember, cellA, cellB, 'UniformOutput', false);

NOTE: My sample data are row vectors, but I had to use the colon operator to reshape them into column vectors when passing them to accumarray (it wants columns). Once distributed into a cell array, each piece of the vector would still be a column vector, and I simply wanted to keep them as row vectors to match the original sample data. The syntax (:).' is a colon reshaping followed by a nonconjugate transpose, ensuring a row vector as a result no matter the shape of x. In this case I probably could have just used .', but I've gotten into the habit of never assuming what the shape of a variable is.

I cannot find a global solution, but the accepted answer of this post helps me to define a helper function for your problem:

function varargout = out2cell(varargin)
[x{1:nargout}]=feval(varargin{:});
varargout = num2cell(x);

I think that you may succeed in calling

splitapply(@(x,y) out2cell(@ismember, x, y), A, B);
Related