将空行插入或追加到 numpy 数组

Posted

技术标签:

【中文标题】将空行插入或追加到 numpy 数组【英文标题】:Insert or append empty rows to a numpy array 【发布时间】:2021-07-14 04:43:18 【问题描述】:

有引用使用np.append 添加到最初为空的数组,例如How to add a new row to an empty numpy array。

相反,我的问题是如何在数组末尾分配额外的空白空间,以便以后可以分配给它。

一个例子:

# Inefficient: The data in new_rows gets copied twice.
array = np.arange(6).reshape(2, 3)
new_rows = np.square(array)
new = np.concatenate((array, new_rows), axis=0)

# Instead, we would like something like the following:

def append_new_empty_rows(array, num_rows):
  new_rows = np.empty_like(array, shape=(num_rows, array.shape[1]))
  return np.concatenate((array, new_rows), axis=0)

array = np.arange(6).reshape(2, 3)
new = append_new_empty_rows(array, 2)
np.square(array[:2], out=new[2:])

但是,np.concatenate() 可能仍会复制空数据数组? 有类似np.append_empty() 的东西吗?

【问题讨论】:

小心,np.empty 制作了一个全新的数组。就像np.zeros 一样,除了元素值是不可预测的。使用它并没有节省任何内存或副本。 那个链接有很多不好的答案。唯一好的坚持使用列表追加,并在最后创建一个数组。 【参考方案1】:

你为什么不这样做:

array = np.arange(6).reshape(2, 3)
n_rows = 4
new = np.vstack([array, np.zeros((n_rows, array.shape[1]) )])

new 数组将是这样的:

array([[0., 1., 2.],
   [3., 4., 5.],
   [0., 0., 0.],
   [0., 0., 0.],
   [0., 0., 0.],
   [0., 0., 0.]])

如果您想要节省一些空间,那么您应该考虑使用concatenate 提供的out 参数。所以它会是这样的:

array = np.arange(6).reshape(2, 3)
n_rows = 4
np.concatenate([array, np.zeros((n_rows, array.shape[1]))], out=array)

如您所见,唯一的分配是array,并且没有创建任何副本。它会覆盖array...

【讨论】:

您的最后一个块引发了 ValueError。 out 不够大。【参考方案2】:

这是你正在做的事情:

制作一个足够大的数组来容纳两个部分。 np.zeros 避免了我们正在节省内存或工作的任何幻想。

In [15]: arr1 = np.zeros((4,3), int)
In [16]: arr1
Out[16]: 
array([[0, 0, 0],
       [0, 0, 0],
       [0, 0, 0],
       [0, 0, 0]])

现在将值从初始 (2,3) 复制到 arr1 的一部分:

In [17]: arr1[:2] = arr
In [18]: arr1
Out[18]: 
array([[0, 1, 2],
       [3, 4, 5],
       [0, 0, 0],
       [0, 0, 0]])

并使用out 将平方值复制到第二部分

In [19]: np.square(arr[:2], out=arr1[2:])
Out[19]: 
array([[ 0,  1,  4],
       [ 9, 16, 25]])

In [21]: arr1
Out[21]: 
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 0,  1,  4],
       [ 9, 16, 25]])

与以下相比,我看不出这如何节省任何精力或内存:

In [22]: np.concatenate((arr, np.square(arr)), axis=0)
Out[22]: 
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 0,  1,  4],
       [ 9, 16, 25]])

concatenate,在幕后必须制作正确大小的结果数组,并将片段复制到其中。如果你想要一个同时包含 arrnp.square(arr) 的数组,那真的没有办法解决。

【讨论】:

我喜欢这个方向。但是,最好使用np.empty() 分配arr1,以节省初始化数组的工作,因为数组的两个部分都将被写入一次?否则,首先用零写入数组,然后用最终数据再次覆盖。 (这就是np.empty()的动机。) 我发现时间差足够小,不值得引起混乱。【参考方案3】:

我发现最快的解决方案是创建一个 empty 更大的数组,然后将输入数组复制到其初始行中:

shape = (1000, 1000)
array = np.ones(shape)
new_shape = (2000, 1000)

def version1():  # Uses np.concatenate().
  new_rows = np.square(array)
  return np.concatenate((array, new_rows), axis=0)

def version2():  # Initializes new array using np.zeros().
  new = np.zeros(new_shape)
  new[:shape[0]] = array
  np.square(array, out=new[shape[0]:])
  return new

def append_new_empty_rows(array, num_rows):
  new = np.empty((array.shape[0] + num_rows, array.shape[1]))
  new[:array.shape[0]] = array
  return new

def version3():  # Initializes new array using np.empty().
  new = append_new_empty_rows(array, num_rows=array.shape[0])
  np.square(array, out=new[array.shape[0]:])
  return new

assert np.all(version1() == version2())
assert np.all(version1() == version3())

%timeit version1()  # 4.34 ms per loop
%timeit version2()  # 3.15 ms per loop
%timeit version3()  # 2.24 ms per loop

【讨论】:

以上是关于将空行插入或追加到 numpy 数组的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在没有numpy的情况下追加二维数组?

未成功追加到空 NumPy 数组

如何将 1d numpy 数组附加到 2d numpy 数组 python

将新行附加到 numpy 数组

向量化numpy追加循环

Python Numpy追加数组而不展平