Вопрос

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

У меня есть двумерный массив 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

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

Это было полезно?

Решение

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

РЕШЕНИЕ 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 группирует строки вальс которые имеют одинаковую дату начала, вместе в ячейки массива ячеек ВалСелл.Переменная новыйВальс будет массив ячеек длиной число (уникальное начало), где каждая ячейка будет содержать результат выполнения нансум в соответствующей ячейке ВалСелл.

РЕШЕНИЕ FOR-LOOP:

[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

Другие советы

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top