MATLAB中的未知长度矩阵?

25

我想要设置一个具有两列的零矩阵,长度可变,可以将while循环的结果输出到其中(以存储调整时间步长的欧拉方法的步骤数据)。长度将由循环的迭代次数确定。

我想知道是否有一种方法可以在运行循环时完成此操作,还是需要先进行设置,如何进行。


此外,如果这是为了课堂作业并且您需要展示迭代过程,则可以在您的欧拉实现中使用sprintf。 - ccook
另一个相关的问题:将向量附加到空的 MATLAB 矩阵 - Amro
4个回答

47

另一种注重性能但仍试图节省空间的方法是预先分配大批内存,根据需要添加更多批次。如果您需要添加大量项目却不知道有多少个,则这非常适用。

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


4
哇咕!一个见地深刻的点子加上能够证实它的测量数据。谢谢。 - Jason S
8
大多数可变大小的方法(例如字符串类)不使用固定块大小,而是通过乘法因子K(通常为K=2)增加大小。这将#分配步骤限制为O(log N),如果您关心内存效率,您始终可以选择K = 1.2或1.1,并处理数学计算命中以权衡效率/ #分配步骤。 - Jason S
5
你可能是正确的。你可以轻松地修改代码来实现这一点。许多参数也可以进行调整:何时增加大小,增加多少,甚至可以设置一个生长因子(从K=1.1开始增加,增加到2)。 - Amro
1
@masad:当然可以!我在文件交换中看到了一些类似的提交。这里有一个由John D'Errico编写的,他在这里简要讨论了它:growdata/growdata2。它的内部实现与我的不同,但你可以模仿接口。 - Amro
还有一件事要提到的是,MATLAB在最近的版本中极大地改善了自动数组增长的性能:http://blogs.mathworks.com/steve/2011/05/20/more-about-automatic-array-growth-improvements-in-matlab-r2011a/,http://stackoverflow.com/a/18864559/97160。因此,天真的方法并不像以前那样糟糕。 - Amro
显示剩余3条评论

15
如果列数固定,你可以在循环内向矩阵中添加行。
例如:
while (....)
   .....
   new_row =[x y] ; % new row with values x & y
   mat = [mat ; new_row]; 

当然,如果您在进入while循环之前知道迭代的次数,预先分配矩阵会更有效率。


非常感谢!我明白了。你会认为在编程单元中他们会教我们一些东西,但是他们却把我们扔给了狼群。感谢你的帮助 :) - Flick
2
使用上面代码的替代语法可以更明确地表明您正在扩展矩阵:mat(end+1,:) = new_row; - nhowe
请查看以下网址,了解有关速度的提示:https://stackoverflow.com/questions/49256309/matlab-euler-explicit-ode-solver-with-adaptable-step-is-there-a-way-to-make-cod/49258006#49258006 - Mefitico

7
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,:) = [];

+1 我经常使用这个。请注意,您也可以只使用计数器,Matlab会自动扩展数组。 - ccook
我开始明白你在做什么以及为什么这样做是高效的。非常有帮助,谢谢。 - Flick

4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接