“增长”(附加)序列对象

时间:2011-10-13 16:51:38

标签: python matlab

在Matlab中,建议不要使用这种算法(“增长数组”)

mine = []
for i=1:100,
    mine = [mine,randn(1)]
end

虽然似乎很多Python的例子都显示了这种算法(但这是一个非常糟糕的例子):

import numpy.random as rand

mine = []
for i in range(100):
    mine.append(rand.random(1)[0])

我想知道为什么会这样 - 有什么区别?

4 个答案:

答案 0 :(得分:7)

区别在于:

  • 在MATLAB中,循环的每次迭代都会重新分配矩阵,将大小增加一,并将整个内容复制到新分配的空间中。
  • Python列表不起作用。分配的空间比任何给定点所需的空间多,并且这个分配的空间以保证追加是在摊销的恒定时间内完成的方式增长。

那就是说,我认为区别主要在于文化:

  • 在MATLAB中使用大型数字矩阵是很常见的,并且一次增加这样的矩阵一个元素(或一行/列)确实很昂贵。
  • 另一方面,没有人会使用Python列表(或列表列表)来表示一个大矩阵:这将非常慢并且会很难使用内存。将使用Numerical Pythonndarray代替,ndarray将提供与MATLAB矩阵完全相同的权衡。

答案 1 :(得分:4)

在Matlab中追加数组显然非常低效(它以二次方运行),而在python中,相应的列表操作更加高度优化。追加到O(1)直到列表变满 - 此时列表的大小加倍以产生更多空间(这是O(n)操作)。这意味着随着列表变长(整体效率为O(1)摊销),追加变得越来越有效。这些优化也可能在Matlab中实现,但似乎它们不是自动完成的。

为了获得更好的性能,python还有collections.deque容器类,支持从任一端有效追加和删除(在两个方向都是O(1))。

答案 2 :(得分:2)

你的两个例子并不完全相同。 Matlab示例将两个列表连接到一个新列表中,每次都创建一个副本,而Python将项目附加到列表中,而不是每次都复制它。实际上,您可以编写与Matlab代码完全相同的Python,例如:

mine = mine + [newitem]

但是你不应该这样做,因为你每次都会复制一份不断增长的名单。这就是为什么列表有.append()方法(也是.extend())。

出于类似的原因,Pythonistas建议您将单个字符串附加到列表中,然后在其上使用``.join(),而不是通过串联构建字符串。

顺便说一句,Python列表总是为额外的项目分配空间,因此当附加新项目时,它们并不总是需要增长。

答案 3 :(得分:2)

您的MATLAB代码可以更好地编写。比较以下实现:

%# preallocation
tic
x = zeros(1,100000); for i=1:100000, x(i) = 99; end
toc

%# appending
tic
x = []; for i=1:100000, x(end+1) = 99; end
toc

%# concatenation
tic
x = []; for i=1:100000, x = [x, 99]; end
toc

我得到以下结果:

Elapsed time is  0.001844 seconds.    %# preallocated vector/matrix
Elapsed time is  0.109597 seconds.    %# appending using "end+1" syntax
Elapsed time is 35.226361 seconds.    %# appending using concatenation

请注意,上述内容是在R2011b上测试的,它引入了对增长矩阵的改进(无需预先分配)。

您还应该检查此previous answer以获得一个结合了预分配但仍允许动态增长的解决方案(想法是以大块大小分配/增长)

另一方面,您应该注意Python列表已经过优化,可以在最后添加项目。如果您在开头插入项目,您将得到非常不同的时间。例如:

>>> from timeit import timeit

>>> timeit('x.insert(0,99)', 'x=[]', number=100000)
5.3840245059078597

>>> timeit('x.append(99)', 'x=[]', number=100000)    # x.insert(len(x),99)
0.039047700196533697