如何使用`cellfun`(MATLAB)应用具有多个参数的函数?

10
使用cellfun,如何将一个函数应用于由mat2cell函数创建的所有单元格?我的函数在另一个文件中定义,在此处它被引用为myFunc。该函数需要两个参数,应该是一个单元格和一个整数。
例如:function H = myFunc(img,Q) 我的代码如下:
% Split into grid and process each cell
width = size(img,2) % get image width
height = size(img,1) % get image height
depth = size(img,3) % get depth
C = mat2cell(img,[height/2 height/2],[width/2 width/2],[depth/2 depth/2]); % divides image into sections
F = cellfun(@myFunc,C);
save(fout,'F');

问题当然在于这一行代码:F = cellfun(@myFunc,C);。我如何将单元格和所选择的整数(例如4)传递到myFunc函数中,以便为每个单元格执行操作?

非常感谢。

3个回答

14

简单地定义一个新的匿名函数,如@(x) myFunc(x,4),并这样使用它:

F = cellfun(@(x) myFunc(x,4), C)

谢谢,就这样了! :) - petehallw

5

使用匿名函数:

F = cellfun(@(Q) myFunc(Q,4),C);

1

最近遇到了这个问题,并注意到在cellfun中,Octave有隐式的单元格参数扩展,而Matlab没有。调用匿名函数比直接调用函数的开销更大(尽管Matlab在这方面不像Octave那么糟糕),所以我发现将参数传递为单元格数组要快一些,这里有一个简单的示例:

abc = {magic(2), magic(3), magic(4)}
abc =
  3×1 cell array
    {2×2 double}
    {3×3 double}
    {4×4 double}
    
def = cellfun (@(x) sum(x,2), abc, "UniformOutput", false) %anonymous function method
def =
  3×1 cell array
    {2×1 double}
    {3×1 double}
    {4×1 double}
def{:}
ans =
     4
     6
ans =
    15
    15
    15
ans =
    34
    34
    34
    34 

将参数展开成一个单元数组并将其作为另一个输入传递会产生相同的正确输出:
def = cellfun (@sum, abc, num2cell(2*ones(size(abc))), "UniformOutput", false) % cell expansion method
def =
  3×1 cell array
    {2×1 double}
    {3×1 double}
    {4×1 double}
def{:}
ans =
     4
     6
ans =
    15
    15
    15
ans =
    34
    34
    34
    34 
    

快速的tic/toc检查显示在Matlab 2021a中这要快一些:

tic; 
for idx = 1:100000
  cellfun(@(x) sum(x,2), abc,"UniformOutput",false); 
end
toc
Elapsed time is 4.017116 seconds.

tic, 
for idx = 1:100000
  cellfun(@sum, abc, num2cell(2*ones(size(abc))),"UniformOutput",false);
end
toc
Elapsed time is 1.217712 seconds

我还没有尝试过使用非简单参数,但是repmat可以对字符串输入执行相同的操作,但是repmat似乎会增加一些开销:

tic
for idx = 1:100000
    cellfun(@sum, abc, repmat({2}, size(abc)),"UniformOutput",false); 
end
toc
Elapsed time is 4.367002 seconds.

也许有更好的扩展方式。请注意,这是一个非常简单的测试案例,使用了一个小数组。随着规模的扩大或添加多个参数,时间节省可能不再成立。此外,对于你使用此方法的每个参数,都会将内存需求乘以输入数组大小。
快速测试表明,使用自定义函数myfunc和matlab函数sum的时间节约相同。

1
在我的电脑上(并且使用稍大的abc,有9个小数组),第二种变体比第一种快大约3倍,但是一个简单的循环又要再快大约4倍。因此,如果您真的关心速度,请不要使用cellfuncellfun适用于较短的代码,而不是速度。我也发现简单的循环更容易阅读,所以我倾向于避免使用cellfun。我的解决方案:res = cell(size(abc)); for ii = 1:numel(abc), res{ii} = sum(abc{ii},2); end. - Cris Luengo
1
谢谢你加入。说实话,我大多数时候使用Octave,但循环仍然很慢。在那里,num2cell版本只比匿名函数快10-15%。Octave允许您只需将{2}放入第二个单元格数组中,它会隐式扩展,这比匿名函数快约2倍。在那里,您的循环运行速度比匿名函数慢约10%。也许有一天他们会让JIT编译器正常工作。 :) - Nick J
有趣。在MATLAB中,“cellfun”是作为M文件实现的(或者说,最后一次我检查时是这样,但那是几年前的事了),因此“cellfun”总是会增加函数调用的开销(包括所有参数检查)和通过句柄重复调用函数的开销,所以它不能比拼写循环更快。我猜在Octave中它没有作为M文件实现。 - Cris Luengo
“>> which cellfun” “'cellfun'是一个内置函数,来自文件libinterp/corefcn/cellfun.cc”,所以你是正确的。” - Nick J

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接