Алгоритм группирования - PullRequest
3 голосов
/ 14 мая 2009

У меня есть код, который работает, но это узкое место, и я застрял, пытаясь понять, как его ускорить. Это в цикле, и я не могу понять, как это векторизовать.

У меня есть двумерный массив vals, который представляет данные временных рядов. Строки - это даты, столбцы - разные серии. Я пытаюсь собрать данные по месяцам для выполнения различных операций с ними (сумма, среднее и т. Д.). Вот мой текущий код:

allDts; %Dates/times for vals.  Size is [size(vals, 1), 1]
vals;
[Y M] = datevec(allDts);
fomDates = unique(datenum(Y, M, 1)); %first of the month dates

[Y M] = datevec(fomDates);
nextFomDates = datenum(Y, M, DateUtil.monthLength(Y, M)+1);

newVals = nan(length(fomDates), size(vals, 2)); %preallocate for speed

for k = 1:length(fomDates);

Эта следующая строка - узкое место, потому что я так много раз ее называю. (Цикл)

    idx = (allDts >= fomDates(k)) & (allDts < nextFomDates(k));
    bucketed = vals(idx, :);
    newVals(k, :) = nansum(bucketed);
end %for

Есть идеи? Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 14 мая 2009

Это сложная проблема для векторизации. Я могу предложить способ сделать это, используя CELLFUN , но я не могу гарантировать, что это будет быстрее для вашей проблемы (вам придется самим рассчитывать время для конкретных наборов данных, которые вы используете). Как обсуждалось в этом другом вопросе SO , векторизация не всегда работает быстрее, чем для циклов. Это может быть очень проблематично, что является лучшим вариантом. С этим отказом от ответственности я предложу вам два решения: версию CELLFUN и модификацию версии for-loop, которая может работать быстрее.

РЕШЕНИЕ CELLFUN:

[Y,M] = datevec(allDts);
monthStart = datenum(Y,M,1);  % Start date of each month
[monthStart,sortIndex] = sort(monthStart);  % Sort the start dates
[uniqueStarts,uniqueIndex] = unique(monthStart);  % Get unique start dates

valCell = mat2cell(vals(sortIndex,:),diff([0 uniqueIndex]));
newVals = cellfun(@nansum,valCell,'UniformOutput',false);

Вызов MAT2CELL группирует строки vals , имеющие одинаковую дату начала, вместе в ячейки массива ячеек valCell . Переменная newVals будет представлять собой массив ячеек длиной цифра (uniqueStarts) , где каждая ячейка будет содержать результат выполнения nansum для соответствующей ячейки valCell .

РЕШЕНИЕ ДЛЯ ПЕТЛИ:

[Y,M] = datevec(allDts);
monthStart = datenum(Y,M,1);  % Start date of each month
[monthStart,sortIndex] = sort(monthStart);  % Sort the start dates
[uniqueStarts,uniqueIndex] = unique(monthStart);  % Get unique start dates

vals = vals(sortIndex,:);  % Sort the values according to start date
nMonths = numel(uniqueStarts);
uniqueIndex = [0 uniqueIndex];
newVals = nan(nMonths,size(vals,2));  % Preallocate
for iMonth = 1:nMonths,
  index = (uniqueIndex(iMonth)+1):uniqueIndex(iMonth+1);
  newVals(iMonth,:) = nansum(vals(index,:));
end
0 голосов
/ 15 мая 2009

Если все, что вам нужно сделать, это сформировать сумму или среднее значение для строк матрицы, где строки суммируются в зависимости от другой переменной (даты), тогда используйте функцию моего консолидатора. Он предназначен для выполнения именно этой операции, сокращая данные на основе значений ряда индикаторов. (На самом деле, консолидатор также может работать с данными n-d и с допуском, но все, что вам нужно сделать, это передать ему информацию о месяце и году.)

Найти консолидатор при обмене файлами на Matlab Central

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