高效的方法来追加numpy数组。

6

我会简单说明。我有一个循环,将新的行附加到一个numpy数组中...这样做的有效方法是什么。

n=np.zeros([1,2])
for x in [[2,3],[4,5],[7,6]]
      n=np.append(n,x,axis=1)

现在的问题是它有一个[0,0]附着在上面,所以我需要通过

来移除它。

   del n[0]

这似乎很愚蠢...因此,请告诉我一种有效的方法来解决这个问题。

   n=np.empty([1,2])

更糟糕的是,它会创建一个未初始化的值。

为什么不直接执行 n = np.array([[2,3],[4,5],[7,6]]) 呢? - BrenBarn
1
这只是一个例子,在我的程序中,每次迭代都会附加一个不同的值。 - user3443615
1
向NumPy数组追加元素本质上是低效的,因此这种方法在性能方面永远不会表现出色。 - BrenBarn
将元素添加到列表中,然后从该列表的列表构建数组会更有效率。直接向数组添加元素是不高效的。 - hpaulj
请也看一下这个问题:https://dev59.com/HYDba4cB1Zd3GeqPKvKW - newtover
显示剩余2条评论
3个回答

10

"为什么使用列表"部分的一点技术解释。

对于一个未知长度的列表,内部问题在于无论其长度如何,它都需要以某种方式适应内存。基本上有两种不同的可能性:

  1. 使用数据结构(链表、某些树形结构等),使得可以为列表中的每个新元素单独分配内存。

  2. 将数据存储在连续的内存区域中。在创建列表时必须分配此区域,并且它必须比我们最初所需的更大。如果我们将更多内容放入列表中,则需要尝试在相同位置分配更多内存。如果不能在同一位置执行此操作,则需要分配更大的块并移动所有数据。

第一种方法使各种花哨的插入和删除选项、排序等成为可能。然而,在顺序读取方面速度较慢且分配更多内存。Python实际上使用第二种方法,列表以“动态数组”的形式存储。有关此信息的更多信息,请参见:

内存中列表的大小

这意味着列表被设计为使用append非常高效。如果事先不知道列表的大小,则无论如何也很难加速。


如果您甚至事先知道列表的最大大小,则最好使用numpy.empty(而不是numpy.zeros)分配一个具有最大大小的 numpy.array,然后使用ndarray.resize在填充了所有数据后缩小数组。

由于某种原因,在使用大型列表时,numpy.array(l) 其中 l 是列表通常较慢,而即使是复制大型数组也非常快(我刚刚尝试创建一个100000000个元素数组的副本;它只花费了不到0.5秒)。

此讨论还有关于不同选项的基准测试:

最快的扩展NumPy数值数组的方法

我没有对numpy.empty+ndarray.resize组合进行基准测试,但两者应该都是微秒级别的操作,而不是毫秒级别。


Python列表有点像同时使用了(1)和(2),因为每个对象都有自己的分配,而列表元素只是对它的引用。与numpy记录数组相比,其中每个记录都以紧凑的方式存储在数组中,使用(2)策略。它们的区别在于它们的分配策略;列表将分配额外的容量。 (1)因素确保列表中的每个插槽本身都很小,因此未使用的容量不会太多成本。 - bluss
我发现在我的情况下至少有一个最好的解决方案是预先分配足够大的空间,然后更改它并移动自定义的“长度”变量。虽然需要更多的工作,但性能是值得的。 - Íhor Mé

6

如果您已经将所有内容放在列表中,有三种方法可以执行此操作:

data = [[2, 3], [4, 5], [7, 6]]
n = np.array(data)

如果您知道最终数组的大小:

exp = np.array([2, 3])    

n = np.empty((3, 2))
for i in range(3):
    n[i, :] = i ** exp

如果您不知道最终数组的大小:

exp = np.array([2, 3])

n = []
i = np.random.random()
while i < .9:
    n.append(i ** exp)
    i = np.random.random()
n = np.array(n)

仅供参考,您可以从n = np.empty((0, 2))开始,但我不建议在循环中附加该数组。


2
所有的方法都使用列表... 难道没有一种完全使用np.arrays的方法吗... numpy的开发者难道不能想出一种方法吗?而且'n=np.empty((0,2))'不起作用。 - user3443615
1
我可以百分之百地保证 n = np.empty((0, 2)) 是可行的。你不必使用列表,但必须使用某些数据结构。你不能从空气中获取数据,它必须在被放入数组之前以某种结构存在(例如文件、另一个数组、列表、元组、double等)。 - Bi Rico
同样在第三种情况下,当您不知道数组的最终大小时,我有意使用了一个列表。Python 列表实际上是作为 动态数组 实现的,这正是您在最后一种情况下想要的。Numpy 数组不是动态数组,因此最好使用列表。 - Bi Rico

0

你可以尝试以下方法:

import numpy as np

n = np.reshape([], (0, 2))
for x in [[2,3],[4,5],[7,6]]:
      n = np.append(n, [x], axis=0)

你可以使用n = np.vstack([n,x])代替np.append。如果在循环内部不需要访问n,我也同意@Bi Rico的观点,可以使用列表。


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