эффективно разделить данные на бункеры - PullRequest
0 голосов
/ 16 января 2019

Я хочу разделить мою переменную data на разные переменные a b и c и применить mean к ячейкам (1-е измерение). Есть ли способ существенно (например, 1x порядка) улучшить этот код с точки зрения скорости? Общая обратная связь приветствуется

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 голосов
/ 16 января 2019

Вы также можете использовать простой цикл for, я не вижу, как другая функция может быть быстрее в этом случае. Функция mean должна в любом случае читать каждое значение, чтобы ...

for ii = 1:numel(start_bins)
    res{ii} = mean(data(start_bins(ii):end_bins(ii),:),1);
end

Я не собираюсь разбивать ячейку на несколько переменных, поскольку ячейка предназначена именно для этого.

0 голосов
/ 16 января 2019

Вы можете использовать умножение матриц:

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
0 голосов
/ 16 января 2019

Вы можете использовать splitapply (accumarray немного дружелюбный младший брат):

% 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 - это ваши a, b и c.

0 голосов
/ 16 января 2019

Оригинальный вопрос: расщепление и усреднение по разному затемнения

Среднее может быть применено перед разбиением, которое сводит данные к вектору, а затем может использоваться 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 делает. См. @ ответ Вулфи .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...