1

这是输入数据:

  % @param Landmarks:
  %           Landmarks should be 1*m struct. 
  %           m is the number of training set.
  %           Landmark(i).data is a n*2 matrix

功能:

  function Landmarks=CenterOfGravity(Landmarks)
  % align center of gravity

  for i=1 : length(Landmarks)
      Landmarks(i).data=Landmarks(i).data - ones(size(Landmarks(i).data,1),1)...
          *mean(Landmarks(i).data);
  end
  end

使用arrayfun的新函数:

  function [Landmarks] = center_to_gravity(Landmarks)
  Landmarks = arrayfun(@(struct_data)...
                          struct('data', struct_data.data - repmat(mean(struct_data.data), [size(struct_data.data, 1), 1]))...
                                              ,Landmarks);
  end %function center_to_gravity

使用分析器时,我发现时间的使用不是我所期望的:

  Function          Total Time    Self Time*
  CenterOfGravity     0.011s      0.004 s
  center_to_gravity   0.029s      0.001 s

有人能告诉我为什么吗?

顺便说一句...我不能将“arrayfun”添加为我的声誉的新标签。

4

3 回答 3

4

使用arrayfun并不能算作“矢量化代码”,正如每篇 Matlab 性能博客文章中所描述的那样。

如果您的.data字段对于地标的所有条目的长度相同,您可以通过首先将所有数据放入单个 DATASIZE-BY-LANDMARKSIZE martix 来矢量化此代码,然后运行此命令

meanRemovedData = bsxfun(@minus, data, mean(data,1));

但是这样你会失去很多代码清晰度。(我很确定它bsxfun通常具有类似矢量化的速度优势,但我今天早上还没有进行任何测试。)


至于为什么,我真的不是问这个问题的合适人选。但是向量化的许多优点都依赖于对连续的内存块执行简单的操作。存储在结构数组中的数据(我相信)存储为指向不同内存位置的指针数组,这就是为什么您可以在Landmarks(i).data不重新分配整个结构数组的情况下更改大小或类的原因。

于 2012-06-23T15:10:41.060 回答
3

感谢 Amro 和 Pursuit 对我的问题的热情。

我从Jan Simon那里得到了Matlab 答案的最佳解决方案:

为什么 arrayfun 没有提高我的结构数组操作性能

有一些点确实可以提高性能:

  1. 令人惊讶的是,SUM/LENGTH 比 MEAN 快
  2. timeit可以给出更准确的结果。
  3. 最快的方法使用这样的技巧:

    m =总和(数据,1)/大小(数据,1);数据(:, 1) = 数据(:, 1) - m(1);

于 2012-06-24T01:54:16.117 回答
1

考虑以下三个实现(全部使用 BSXFUN 进行矢量化):

function s = func1(s)
    for i=1:numel(s)
        s(i).data = bsxfun(@minus, s(i).data, mean(s(i).data));
    end
end

function v = func2(s)
    v = arrayfun(@(ss) bsxfun(@minus,ss.data,mean(ss.data)), ...
        s, 'UniformOutput',false);
    v = struct('data',v);
end

function v = func3(s)
    v = arrayfun(@(ss) struct('data',bsxfun(@minus,ss.data,mean(ss.data))), ...
        s, 'UniformOutput',true);
end

解释:

  • 首先使用 for 循环遍历结构数组。
  • 第二个使用 ARRAYFUN 返回数据矩阵的元胞数组,然后将其传递给 STRUCT 以构建结构数组。
  • 最后一个使用 ARRAYFUN 并在每次迭代时直接构建一个结构。

这是一个比较时间的简单测试:

function testArrayStruct()
    %# sample array of structures
    s = struct('data',[]);
    for i=5000:-1:1
        s(i).data = rand(randi(1000),2);
    end

    %# timing
    tic; v1 = func1(s); toc
    tic; v2 = func2(s); toc
    tic; v3 = func3(s); toc

    %# check all have the same output
    assert(isequal(v1,v2,v3))
end

结果:

Elapsed time is 0.357796 seconds.         %# func1
Elapsed time is 0.427568 seconds.         %# func2
Elapsed time is 0.537971 seconds.         %# func3

所以你可以看到基于循环的解决方案实际上是最快的..

于 2012-06-23T22:47:18.687 回答