加快arrayfun

时间:2015-02-17 09:54:25

标签: matlab

我有一个非常大的大约1100万行的Matlab表,我想重新排列,为每个变量的每个实例都有一个单元格数组。以下较小的数据集将说明我的问题:

Data = table(repmat(randperm(50).',200,1),rand(10000,1),'VariableNames',{'ID','VAR'});

我能够通过以下命令执行任务,但是当应用于我的真实表时它很慢:

UniID = unique(Data.ID);

CellData = arrayfun(@(x)Data(Data.ID==x,:),UniID,'UniformOutput',false);

如何优化执行时间?

1 个答案:

答案 0 :(得分:3)

在此之后您可能想要进行一些处理,请考虑使用:

B = varfun(@(x) {x}, Data, 'GroupingVariables', 'ID');

如果您将mean更改为@(x) {x},您可以使用此功能将值分组为如上所示的组,或直接应用某些功能,如@mean。这应该是最清晰的解决方案,但它不会给你任何速度提升。


但是,如果不使用表格,可能会获得一点速度增益,但只需使用数组。而不是'GroupingVariables',您可以使用accumarray

如果您的Data.ID已经是正整数,则不需要任何预处理步骤(如果它们不使用:[~,~,newID] = unique(ID))并且可以使用:

accumarray(Data.ID, Data.VAR, [], @(x) {x})

如果您的表只有两个变量,这就足够了。如果您要处理多个变量,则必须使用类似的东西:

accumarray(Data.ID, 1:size(Data,1) ,[], @(I) {Data(I,:)})

这两者都可能改变每个细胞条目的内部排序。如果您不想这样做,请使用accumarray的{​​{3}}。

由于表数据结构有一些开销,如果你不使用Data表来访问值,这可能会更快,但数组本身:

VAR1 = rand(100000,1);
VAR2 = rand(100000,1);
ID = repmat(randperm(50).',2000,1);
VARsPartitioned = accumarray(ID, 1:numel(ID) ,[], @(I) {[VAR1(I,:), VAR2(I,:)]});

对于一百万行和5000个不同的ID,我得到了这些结果:

arrayfun:                ~30 seconds
varfun:                  ~30 seconds
accumarray using table:  ~3 seconds
accumarray using arrays: ~0.3 seconds

PS:您还可以使用@mean@std直接使用accumarray,而无需在第一步中对变量进行分组。