Matlab: Ускоренная петля, применяемая к каждому из 820 000 элементов

Вопрос:

У меня есть набор данных о дождевых осадках со стоимостью каждые 15 минут в течение многих лет, что дает 820 000 строк. Цель (в конечном счете) моего кода – создать столбцы, которые классифицируют данные, которые затем могут быть использованы для извлечения соответствующих фрагментов данных для дальнейшего анализа.

Я новичок в Matlab и буду признателен за помощь!

Первые шаги я получил достаточно быстро. Однако некоторые шаги очень медленные.

Я попробовал предустановочные массивы и использовал самый низкий intX (8 или 16 в зависимости от ситуации), но другие шаги настолько медленны, что они не завершаются.

Медленные – для циклов, но я не знаю, можно ли их векторизовать/разделить на куски/что-нибудь еще, чтобы ускорить их.

У меня есть переменный “дождь”, который содержит значение для каждого временного шага/строки. Я создал переменную “состояние” 0, если нет дождя, и 1, если есть дождь. Также переменная называется “begin”, которая имеет 1, если это первая строка бури, а 0, если нет.

Первый медленный цикл – создать переменную “заклинание” – дать каждому дождю шторм число.

% Generate blank column for spell of size (rain) - preallocate
spell = zeros(size(st),1,'int16');

% Start row for analysis
x=1;

% Populate "spell" variable with a storm number in each row of rain, for the storm number it belongs to (storm number calculated by adding up the number of "begin" values up to that point

for i=1:size(state)
if(state(x)==1)
spell(x) =  sum(begin(1:x));
end
x=x+1;
end

Следующий этап – длина каждой бури. Первые шаги достаточно быстры.

 % List of storm numbers

spellnum = unique(spell);

% Length of each spell
spelllength = histc(spell,spellnum);

Последний шаг ниже (цикл for) слишком медленный и просто сбой.

 % Generate blank column for length

length = zeros(size(state),1,'int16');

% Starting row

x = 1;

% For loop to output the total length of the storm for each row of rain within that storm

for i=1:size(state)

for j=1:size(state)
position = find(spell==x);

for k=1:size(state)
length(position) = spelllength(x+1);
end
end

x=x+1;

end

Можно ли сделать это более эффективным?

Извините, если примеры уже существуют – я не уверен, как будет вызван этот процесс! Спасибо заранее.

Лучший ответ:

Комбинация кода, который я использовал, представляет собой смесь из @CST_Link и @Sifu. Большое спасибо за Вашу помощь! Я не думаю, что Stackoverflow позволяет мне принимать два ответа, поэтому для ясности, объединив все это, вот код, который каждый помог мне создать!

Единственная медленная часть – цикл for в третьем блоке, но это все еще работает через несколько минут, что достаточно для меня и бесконечно лучше, чем моя попытка.

Первый блок:

%% Spell
%spell is cumulative sum of begin

spell = cumsum(begin);

%% start row
x=1;

%% Replace all rows of spell with no rain with 0
spell(state==0)=0

Второй блок (без изменений, кроме лучших имен переменных):

%%  Spell number = all values of spell

spell_num = unique(spell);

%% Spell length = how many of each value of spell
spell_length = histc(spell,spell_num);

Третий блок:

%% Generate blank column for spell of size (state)
 spell_length2 = zeros(length(state),1);

%%
for x=1:length(state)
    position = find(spell==x);
    spell_length2(position) = spell_length(x+1);
end

Ответ №1

Памятная записка советы по распределению/перераспределению:

  1. попытайтесь создать результаты непосредственно из выражения (в конечном итоге обрезая другой, более общий результат);
  2. если 1. невозможно, попробуйте заранее выделить (когда у вас есть верхний предел для результата);
  3. если 2. невозможно попытаться вырастить массивы ячеек, а не массивные матрицы (потому что матрица требует смежной области памяти)

Советы по выбору типа:

  1. старайтесь использовать всегда double промежуточные результаты, потому что это основной числовой тип данных в MATLAB; избегая конверсий взад и вперед;
  2. используйте другие типы для промежуточных результатов только в том случае, если существует ограничение памяти, которое можно уменьшить с помощью типа меньшего размера.

Советы по линеаризации:

  1. самая быстрая линеаризация использует матричные или элементарные основные алгебраические операции в сочетании с логической индексацией.
  2. циклы не так уж плохи, начиная с MATLAB R2008;
  3. наихудшими функциональными функциями обработки элементов являются arrayfun, cellfun и structfun с анонимными функциями, потому что анонные функции оценивают самые медленные;
  4. старайтесь не вычислять одни и те же вещи дважды, даже если это дает вам лучшую линеаризацию.

Первый блок:

% Just calculate the entire cumulative sum over begin, then
% trim the result. Check if the cumsum doesn't overflow.
spell           = cumsum(begin);
spell(state==0) = 0;

Второй блок:

% The same, not sure how could you speed this up; changed
% the name of variables to my taste, though.
spell_num    = unique(spell);
spell_length = histc(spell,spell_num);

Третий блок:

% Fix the following issues:
%   - the most-inner "for" does not make sense because it rewrites
%     several times the same thing;
%   - the same looping variable "i" is re-used in three nested loops,
%   - thename of the standard function "length" is obscured by declaring
%     a variable named "length".
for x = 1:numel(spell_num)
storm_selector = (spell==spell_num(x));
storm_length(storm_selector) = spell_length(x+1);
end;

Ответ №2

для первой части, если я следую тому, что вы делаете
Я создал некоторые данные, соответствующие вашему описанию для тестирования. скажите, пожалуйста, если я что-то пропустил

state=[ 1 0 0 0 0 1 1 1 1 1 0 1 0 0 1 0 1 1 1 1 0];
begin=[ 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0];
spell = zeros(length(state),1,'int16');
%Start row for analysis
x=1;

% Populate "spell" variable with a storm number in each row of rain, for the storm number it belongs to (storm number calculated by adding up the number of "begin" values up to that point

for i=1:length(state)
if(state(x)==1)
spell(x) =  sum(begin(1:x));
end
x=x+1;
end
% can be accomplished by simply using cumsum ( no need for extra variables if you are short in memory)


spell2=cumsum(begin);
spell3=spell2.*(state==1);

и выход для заклинания и заклинания 3, как показано

[spell.'; spell3]

0      0      0      0      0      1      1      1      1      1      0      2      0      0      2      0      3      3    3      3      0
0      0      0      0      0      1      1      1      1      1      0      2      0      0      2      0      3      3      3      3      0

Ответ №3

Почему бы вам не сделать это вместо этого?

% For loop to output the total length of the storm for each row of rain within that storm

for x=1:size(state)
position = find(spell==x);
length(position) = spelllength(x+1);
end

Я заменил i итератор на x, который удаляет 2 строки и некоторые вычисления.
Затем я приступил к удалению двух вложенных циклов, поскольку они были беспорядочными бесполезными (каждый цикл выдавал бы одно и то же)
Это уже хорошее начало.

Оцените статью
TechArks.Ru
Добавить комментарий