哪些numpy操作会复制数据,哪些会改变数据?

4

有没有一个经验法则可以知道在 numpy.ndarray 上哪些操作会产生值的 副本,哪些会就地修改它们呢?

我对 numpy 还比较陌生,肯定会走弯路,但我想知道是否有普遍的原则推动着可变性,这可能有助于加速我的学习。


1
没有太多真正的inplace numpy操作。我能想到的只有直接形状赋值、inplace排序、调整大小、+=样式数学和索引赋值。 - hpaulj
没有明显的经验法则,但变异器列表很短。我认为我在我的答案中几乎列出了全部列表,所以如果有任何困惑,只需回到这里查看即可。 - tel
1
@tel 我认为对于我来说,"几乎永远不会变异"和"几乎总是返回一个视图"的经验法则非常有帮助,特别是在我刚开始学习时。底层问题是避免无意中更改我想要视为不变的东西(因为其他方法也会使用它),并避免不必要的性能损失。在您的回答之前,我还没有明确区分视图和副本,所以这也是一个非常有用的见解 :) 就我而言,数组就像是基于“基础”的映射,可以轻松创建现有基础上的新映射,这本质上就是创建视图。 - scanny
基本上就是这样。我要补充的是,有些数组是“基础”,也就是说它们正式拥有其底层内存缓冲区的所有权。值得庆幸的是,在绝大多数情况下,数组是否拥有自己的数据几乎没有任何区别(尽管还有一个经验法则:对拥有自己数据的数组进行操作“更有可能”返回一个视图而不是副本(尽管在某些情况下,对视图进行操作确实会返回一个视图))。 - tel
1个回答

6

原地修改的函数

相对较少的numpy函数会在原地修改数组。大部分情况下,numpy函数返回数组视图,如果不能返回视图,则返回副本。

以下是一份详尽的列表(从文档中摘取)列出了能够在原地修改的函数/方法:

  • ndarray.resize
  • ndarray.sort
  • 所有原地二元操作符(例如+=*=^=等)
  • numpy.fill_diagonal
  • numpy.random.shuffle
  • ndarray.partition

以下是一份可选地在原地修改的函数/方法列表:

  • ndarray.byteswap
  • numpy.nan_to_num

某些赋值语句也会在原地修改数组。您可以通过对切片进行赋值(例如arr[...] = 1将数组中的每个值设置为1)来更改数组中的值,并且您可以通过直接将新形状分配给.shape来重新整形数组,例如arr.shape = (2,3)(不总是有效,请参见此处的说明)。

还有一些支持out关键字参数的函数。如果将同一数组作为输入和out传递给这些函数,则它们将像变异体一样运行。

请注意,我可能会漏掉一两个没有在文档中明确标记的原地修改器。无论如何,列表很短,因此没有太多需要记忆的内容。

有关视图与副本返回值的说明

在过去几年中,numpy开发人员的目标之一似乎是使numpy函数和ndarray方法更常见地返回视图而不是副本。现在,可以合理地假设,如果numpy函数/方法可以返回视图,则默认情况下会返回视图。

例如,ndarray.flattenndarray.ravel 执行了相同的操作(返回一个扁平化的数组)。然而,`ndarray.flatten` 的文档明确表示它会返回一个副本,而`ndarray.ravel` 的文档则表示只在必要时才返回副本。
在实际代码中,可以通过比较结果的 .base 的 `id` 和原始数组的 `id` 来判断操作是否产生了视图或副本。例如:
arr = np.array([[1, 2],
                [3, 4],
                [5, 6]])

arrflat = arr.flatten()
assert arrflat.base is not arr

arrravel = arr.ravel()
assert arrravel.base is arr

我不确定他是否在询问视图与副本。它们都是新的数组对象。 - hpaulj

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