高效地将数据拆分为垃圾箱

时间:2019-01-16 13:18:19

标签: matlab performance

我想将data变量拆分为不同的变量a bc,然后将mean应用于垃圾箱(第一维)。有没有办法在速度上大幅度提高(例如1倍数量级)此代码?欢迎一般反馈

data=rand(20,1000); %generate data
bins=[5 10 5]; %given size of bins
start_bins=cumsum([1 bins(1:end-1)]);
end_bins=cumsum([bins]);
%split the data into 3 cell arrays and apply mean in 1st dimension
binned_data=cellfun(@(x,y) mean(data(x:y,:),1),num2cell(start_bins),num2cell(end_bins),'uni',0);
%data (explicitly) has be stored into different variables
[a,b,c]=deal(binned_data{:});
whos a b c
  Name      Size              Bytes  Class     Attributes

  a         1x1000             8000  double              
  b         1x1000             8000  double              
  c         1x1000             8000  double              

4 个答案:

答案 0 :(得分:3)

原始问题:沿不同暗角进行分割和平均

可以在分割之前应用均值,从而将数据简化为向量,然后可以使用accumarray

binned_data = accumarray(repelem(1:numel(bins), bins).', mean(data,2), [], @(x){x.'});

编辑后的问题:沿相同暗淡

进行分割和平均

accumarray 1 不适用于矩阵数据。但是您可以使用sparse,它会自动累积与相同索引对应的数据值:

ind_rows = repmat(repelem((1:numel(bins)).', bins), 1, size(data,2));
ind_cols = repmat(1:size(data,2), size(data,1), 1);
binned_data = sparse(ind_rows, ind_cols, data);
binned_data = bsxfun(@rdivide, binned_data, bins(:));
binned_data = num2cell(binned_data, 2).';

但是splitapply确实如此。参见@Wolfie's answer

答案 1 :(得分:3)

您可以使用矩阵乘法:

r = 1:numel(bins);
result = (r.' == repelem(r,bins)) * data .* (1./bins(:));

如果要将输出作为单元格:

result = num2cell(result,2);

对于大型矩阵,最好使用稀疏矩阵:

result = sparse(r.' == repelem(r,bins)) * data .* (1./bins(:));

注意:在早期版本的MATLAB中,您应该使用bsxfun

result = bsxfun(@times,bsxfun(@eq, r.',repelem(r,bins)) * data , (1./bins(:)))

这是Octave中三种建议方法计时的结果:

矩阵乘法:

0.00197697 seconds

Accumarray:

0.00465298 seconds

Cellfun:

0.00718904 seconds

编辑: 对于200 x 100000矩阵:

矩阵乘法:

0.806947 seconds   sparse: 0.2331  seconds

Accumarray:

0.0398011 seconds

Cellfun:

0.386079  seconds

答案 2 :(得分:3)

您可以使用splitapplyaccumarray的友善小弟弟):

% Your example
data = rand(20,1000); % generate data
bins = [5 10 5];      % given size of bins

% Calculation
bins = repelem(1:numel(bins), bins).'; % Bin sizes to group labels
binned_data = splitapply( @mean, data, bins ); % splitapply for calculation

binned_data的行是您的abc

答案 3 :(得分:1)

您还可以使用一个简单的for循环,在这种情况下,我看不出另一个函数可以更快。函数end在任何情况下都必须读取每个值,以便...

mean

我不会将单元格拆分为多个变量,因为一个单元格正是为此目的而设计的。