Numpy concatenate很慢:任何替代方法?

时间:2016-07-19 23:47:54

标签: arrays performance numpy concatenation

我正在运行以下代码:

for i in range(1000)
    My_Array=numpy.concatenate((My_Array,New_Rows[i]), axis=0)

上面的代码很慢。有没有更快的方法?

5 个答案:

答案 0 :(得分:14)

这基本上是基于数组的所有算法中发生的事情。

每次更改数组的大小时,都需要调整大小,并且需要复制每个元素。这也发生在这里。 (一些实现保留了一些空槽;例如,随着每个增长,内部存储器的空间加倍)。

  • 如果您在np.array创建时获得数据,只需一次添加这些数据(内存只分配一次!)
  • 如果没有,请使用链接列表(允许O(1)追加操作)收集它们。然后立即在你的np.array中读取它(再次只有一个内存分配)。

这不是一个特定于numpy的主题,而是关于数据结构的更多内容。

编辑,因为这个相当含糊的答案得到了一些赞成,我觉得有必要明确我的链表方法就是一个可能的例子。正如评论中所指出的,python的列表更像数组(绝对不是链表)。但核心事实是:python中的list.append()是fast(摊销:O(1)),而numpy-arrays则不然!关于docs中的内部构件还有一小部分:

  
    

如何实施清单?

         

Python的列表实际上是可变长度的数组,而不是Lisp样式的链表实现使用对其他对象的连续引用数组,并在列表头结构中保留指向此数组和数组长度的指针。

         

这使得列表a [i]为索引编制索引,其成本与列表大小或索引值无关。

         

添加或插入项目时,将调整引用数组的大小。 应用一些聪明才能提高重复附加项目的效果;当必须增长数组时,会分配一些额外的空间,因此接下来的几次不需要实际调整大小。

  

(我的加粗注释)

答案 1 :(得分:6)

这取决于New_Rows[i]是什么,以及你想要什么样的数组。如果你从列表(或1d数组)开始,你想要端到端地连接(做一个长的1d数组),只需将它们连接起来。 Concatenate获取任何长度的列表,而不仅仅是2个项目。

 np.concatenate(New_Rows, axis=0)

或者可能使用中间列表理解(为了更大的灵活性)

 np.concatenate([row for row in New_Rows])

或更接近你的例子。

 np.concatenate([New_Rows[i] for i in range(1000)])

但如果New_Rows元素的长度相同,并且您想要一个二维数组,每行一个New_Rows值,np.array做得很好:

 np.array(New_Rows)
 np.array([i for i in New_Rows])
 np.array([New_Rows[i] for i in range(1000)])

np.array主要用于从列表列表构建数组。

np.concatenate也可以在2d中构建,但输入需要以2d开头。 vstackstack可以照顾到这一点。但是所有这些stack函数都使用某种列表推导,然后是concatenate

通常,迭代或附加列表会更好/更快,并且只应用np.array(或连接)一次。 appending列表很快;比制作​​新阵列要快得多。

答案 2 :(得分:0)

也许创建一个具有正确大小的空数组,然后填充它? 如果您具有相同尺寸的数组列表,则可以

import numpy as np 
arr = np.zeros((len(l),)+l[0].shape) 
for i, v in enumerate(l):
   arr[i] = v

对我来说工作快得多,只需要分配一个内存

答案 3 :(得分:0)

我认为@thebeancounter的解决方案是解决之道。 如果您事先不知道numpy数组的确切大小,也可以采用类似于在C ++中实现矢量类的方法。

更具体地说,您可以将numpy ndarray包装到一个新的类中,该类的默认大小大于您当前的需要。当numpy数组几乎完全填充后,将当前数组复制到更大的数组。

答案 4 :(得分:-1)

假设您有大量的2D numpy数组,具有相同的列数和不同的行数:

x = [numpy_array1(r_1,c),......,numpy_arrayN(r_n,c)]

像这样串联:

while len(x) != 1:
    if len(x) == 2:
        x = np.concatenate((x[0], x[1]))
        break
    for i in range(0, len(x), 2):
        if (i+1) == len(x):
            x[0] = np.concatenate((x[0], x[i]))
        else:
            x[i] = np.concatenate((x[i], x[i+1]))

    x = x[::2]