【问题标题】:Speed up arrayfun加快阵列乐趣
【发布时间】:2015-02-17 09:54:24
【问题描述】:

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

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);

我可以做些什么来优化执行时间?

【问题讨论】:

  • 也许将Data.ID 放入一个单独的变量中?
  • 好的,谢谢,我试试看!
  • 也可以尝试使用 for 循环而不是 arrayfun,开销可能会更少...
  • 摆脱table 可能是加快这一进程的最佳方式。
  • Data.ID 放入一个单独的变量中,做了一点,但不是很多。我也可以试试 for 循环。我的真实表格有很多变量,其中一些不是数字,所以我不知道如何避免表格。

标签: matlab


【解决方案1】:

由于您可能希望在此之后进行一些处理,请考虑使用:

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

如果您将@(x) {x} 更改为@mean,您可以使用它来将值划分为如上所述的组,或者直接应用mean 之类的函数。这应该是最清晰的解决方案,但它不会给您带来任何速度提升。


但是,如果您不使用表,而只是使用数组,那么您可能会获得一点速度提升。你可以使用accumarray,而不是'GroupingVariables'

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

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

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

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

这两种方法都可能会打乱每个单元格条目的内部顺序。如果您不想要这个,请使用this stable version of accumarray

由于表数据结构有一些开销,如果您不使用 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@stdaccumarray 一起使用,而无需在第一步中对变量进行分组。

【讨论】:

  • 谢谢!看起来要避免 tablearrayfun,而使用 accumarray 是要走的路...
  • 在我的真实数据中,ID 是正整数,但它们不是从 1 到 50 连续运行,而是可能从 7100 开始,并且从 7100 开始不连续。我不知道如何我调整了你最后的解决方案?
  • @Mace:如果我理解正确,你不希望有任何“漏洞”;是的,你可以在那里使用unique。如果你不介意这些洞,它应该可以工作。
猜你喜欢
  • 2017-02-08
  • 2016-11-05
  • 2010-12-24
  • 2013-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-02
  • 2015-04-13
相关资源
最近更新 更多