Матрица неизвестной длины в MATLAB?

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

Мне интересно, есть ли способ сделать это, пока я запускаю цикл, или мне нужно настроить его для начала, и как это сделать.


person Flick    schedule 10.10.2009    source источник
comment
Кроме того, если это для назначения класса, и вам нужно показать итерации; вы можете использовать sprintf в своей реализации Эйлера.   -  person ccook    schedule 10.10.2009
comment
Другой связанный вопрос: Добавление вектора к пустой матрице MATLAB   -  person Amro    schedule 01.08.2012


Ответы (4)


если количество столбцов фиксировано, вы всегда можете добавить строки в свою матрицу (внутри цикла)

e.g.

while (....)
   .....
   new_row =[x y] ; % new row with values x & y
   mat = [mat ; new_row]; 

конечно, если вы знаете количество итераций перед циклом while, более эффективно предварительно выделить матрицу

person LiorH    schedule 10.10.2009
comment
Большое тебе спасибо! Для меня это имеет смысл. Вы думаете, что для программиста они научат нас чему-то, но вместо этого они бросают нас на произвол судьбы. Спасибо, что спасли меня :) - person Flick; 10.10.2009
comment
Использование альтернативного синтаксиса для последней строки приведенного выше кода делает более очевидным, что вы расширяете матрицу: mat(end+1,:) = new_row; - person nhowe; 18.04.2013
comment
См. Несколько советов по скорости на stackoverflow.com/questions/49256309/ - person Mefitico; 05.10.2018

Другой подход, ориентированный на производительность при одновременном стремлении к экономии места, - это предварительное выделение памяти большими пакетами с добавлением дополнительных пакетов по мере необходимости. Это хорошо подходит, если вам нужно добавить большое количество элементов, не зная заранее, сколько элементов.

BLOCK_SIZE = 2000;                          % initial capacity (& increment size)
listSize = BLOCK_SIZE;                      % current list capacity
list = zeros(listSize, 2);                  % actual list
listPtr = 1;                                % pointer to last free position

while rand<1-1e-5                           % (around 1e5 iterations on avrg)
  % push items on list
  list(listPtr,:) = [rand rand];            % store new item
  listPtr = listPtr + 1;                    % increment position pointer

  % add new block of memory if needed
  if( listPtr+(BLOCK_SIZE/10) > listSize )  % less than 10%*BLOCK_SIZE free slots
    listSize = listSize + BLOCK_SIZE;       % add new BLOCK_SIZE slots
    list(listPtr+1:listSize,:) = 0;
  end
end
list(listPtr:end,:) = [];                   % remove unused slots

РЕДАКТИРОВАТЬ. Для сравнения времени рассмотрим следующие случаи:

  1. Тот же код, что и выше, для 50000 итераций.
  2. Предварительное размещение всей матрицы: list = zeros(50000,2); list(k,:) = [x y];
  3. Динамическое добавление векторов в матрицу: list = []; list(k,:) = [x y];

На моей машине результаты были:

1) Прошедшее время составляет 0,080214 секунды.
2) Истекшее время составляет 0,065513 секунды.
3) Истекшее время составляет 24,433315 секунд.


Обновлять:

После обсуждений в комментариях я повторно провел несколько тестов с использованием последней версии R2014b. Вывод состоит в том, что последние версии MATLAB значительно улучшили производительность автоматического роста массива!

Однако есть загвоздка; массив должен расти по последнему измерению (столбцы в случае 2D-матриц). Вот почему добавление строк, как было задумано изначально, все еще слишком медленно без предварительного выделения. Здесь действительно может помочь предложенное выше решение (путем расширения массива партиями).

Полный набор тестов см. Здесь: https://gist.github.com/amroamroamro/0f104986796f2e0aa618

person Amro    schedule 10.10.2009
comment
уууу! проницательная точка + измерения для подтверждения. благодаря. - person Jason S; 11.10.2009
comment
p.s. большинство методов переменного размера (например, строковых классов) не используют фиксированный размер блока, а скорее увеличивают размер на множитель K (обычно K = 2). Это ограничивает количество шагов распределения до O (log N), и если вы заботитесь об эффективности памяти, вы всегда можете выбрать K = 1,2 или 1,1 и обработать результат математического вычисления, чтобы найти компромисс между эффективностью / количеством шагов распределения. - person Jason S; 11.10.2009
comment
вы, вероятно, правы ... вы можете легко изменить код, чтобы сделать это. Также можно настроить ряд параметров: когда увеличивать размер, на сколько, возможно, даже на коэффициент роста (начните с K = 1,1 и увеличьте до 2) - person Amro; 11.10.2009
comment
У меня есть вопрос по этому поводу, можно ли преобразовать его в класс? - person masad; 29.11.2014
comment
@masad: конечно можно! Я видел несколько материалов на File Exchange, которые делают нечто подобное. Вот письмо Джона Д'Эррико, которое он кратко обсудил здесь: growdata / growdata2. Внутри он реализован иначе, чем у меня, но вы можете имитировать интерфейс. - person Amro; 30.11.2014
comment
И последнее, о чем стоит упомянуть; MATLAB значительно улучшил производительность автоматического увеличения массива в последних версиях: blogs.mathworks.com/steve/2011/05/20/, stackoverflow.com/a/18864559/97160. Так что наивный подход уже не так плох, как раньше .. - person Amro; 30.11.2014
comment
@amro Большое спасибо за ваш ответ. Я написал класс с использованием дескрипторов Matlab, однако он намного медленнее, чем ваш метод, упомянутый выше. Помимо определения класса как свойств и методов, я напрямую копирую ваш код. Он выполняется за 4,0 секунды по сравнению с 0,05 секунды при прямом использовании приведенного выше кода. Вот ссылка на мою реализацию: github.com/masad801/dynamicArray, любые мысли по этому поводу действительно помогут ! - person masad; 30.11.2014
comment
@masad: Я провел несколько собственных тестов. Вот полный код: gist.github.com/amroamroamro/0f104986796f2e0aa618 (см. Мои примечания в файл README) - person Amro; 02.12.2014

MATLAB использует динамическую типизацию с автоматическим управлением памятью. Это означает, что вам не нужно объявлять матрицу фиксированного размера перед ее использованием - вы можете изменить ее по мере продвижения, и MATLAB будет динамически выделять вам память.

НО способом более эффективно сначала выделить память для матрицы, а затем затем использовать ее. Но если вашим программам нужна такая гибкость, дерзайте.

Я предполагаю, что вам нужно продолжать добавлять строки в свою матрицу. Следующий код должен работать.

Matrix = [];

while size(Matrix,1) <= 10
    Matrix = [Matrix;rand(1,2)];
end

disp(Matrix);

Здесь мы динамически перераспределяем пространство, необходимое для Matrix, каждый раз, когда вы добавляете новую строку. Если вы заранее знаете, скажем, верхнюю границу количества строк, которые вы собираетесь иметь, вы можете объявить Matrix = zeros(20,2), а затем постепенно вставлять каждую строку в матрицу.

% Allocate space using the upper bound of rows (20)
Matrix = zeros(20,2);
k = 1;
for k = 1:10
   Matrix(k,:) = rand(1,2);
end
% Remove the rest of the dummy rows
Matrix(k+1:end,:) = [];
person Jacob    schedule 10.10.2009
comment
+1 Я постоянно этим пользуюсь. Обратите внимание, что вы также можете просто использовать счетчик, и Matlab будет увеличивать массив. - person ccook; 10.10.2009
comment
Я начинаю понимать, что вы делаете и почему это эффективно. Очень полезно, спасибо. - person Flick; 10.10.2009

Другой вариант того же самого, что написал Джейкоб.

for counter = 1:10
    Matrix(counter,:) = rand(1,2);
end
disp(Matrix);

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

Это также может быть интересно: http://www.mathworks.com/help/matlab/math/resizing-and-reshaping-matrices.html#f1-88760

person ccook    schedule 10.10.2009