是否使用高级索引复制数组数据?

时间:2013-03-28 20:41:43

标签: python numpy copy

我正在慢慢地尝试理解numpy中viewcopy之间的区别,以及可变类型和不可变类型之间的区别。

如果我使用'advanced indexing'访问数组的一部分,则应该返回副本。这似乎是真的:

In [1]: import numpy as np
In [2]: a = np.zeros((3,3))
In [3]: b = np.array(np.identity(3), dtype=bool)

In [4]: c = a[b]

In [5]: c[:] = 9

In [6]: a
Out[6]: 
array([[ 0.,  0.,  0.],
       [ 0.,  0.,  0.],
       [ 0.,  0.,  0.]])

由于c只是一个副本,因此它不会共享数据,更改数据不会改变a。然而,这让我感到困惑:

In [7]: a[b] = 1

In [8]: a
Out[8]: 
array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

所以,似乎即使我使用高级索引,分配仍然将左边的东西视为视图。显然,第2行中的a与第6行中的a是相同的对象/数据,因为变异c对它没有影响。

所以我的问题是:第8行中的a是与之前相同的对象/数据(当然不算对角线)还是副本?换句话说,a的数据是复制到新的a,还是其数据发生了变异?

例如,是这样的:

x = [1,2,3]
x += [4]

或者喜欢:

y = (1,2,3)
y += (4,)

我不知道如何检查这一点,因为在任何一种情况下,a.flags.owndata都是True。如果我以一种令人困惑的方式考虑这个问题,请随时详细说明或回答不同的问题。

3 个答案:

答案 0 :(得分:8)

执行c = a[b]时,调用a.__get_item__作为唯一参数b,并将返回的内容分配给c

当您执行a[b] = c时,a.__setitem__作为参数调用bc,并且会无声地丢弃返回的内容。

因此尽管具有相同的a[b]语法,但两个表达式都在做不同的事情。您可以继承ndarray,重载这两个函数,并使它们的行为不同。正如numpy中的默认情况一样,前者返回一个副本(如果b是一个数组),但后者会修改a

答案 1 :(得分:4)

是的,它是同一个对象。以下是您检查的方式:

>>> a
array([[ 0.,  0.,  0.],
       [ 0.,  0.,  0.],
       [ 0.,  0.,  0.]])
>>> a2 = a
>>> a[b] = 1
>>> a2 is a
True
>>> a2
array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

在Python中分配一些表达式与仅读取该表达式的值不同。当您使用等号右侧的c = a[b] a[b]时,它会返回一个新对象。当您a[b] = 1,并且等号左侧有a[b]时,它会修改原始对象。

事实上,像a[b] = 1 这样的表达式无法更改a绑定的名称。处理obj[index] = value的代码只能知道对象obj,而不是用于引用该对象的名称,因此它无法更改该名称所指的内容。

答案 2 :(得分:0)

这似乎是一种常见的误解,引用了官方文件: (https://scipy-cookbook.readthedocs.io/items/ViewsVsCopies.html

  

这里的经验法则可以是:在左值索引的上下文中(即   索引放在作业的左侧值中),   没有创建数组的视图或副本(因为没有必要)。   但是,对于常规值,上述用于创建视图的规则会   申请。

换句话说,viewcopy的概念仅是指从numpy对象检索值的情况。