一个numpy数组的视图是一个副本?

时间:2016-08-04 13:32:21

标签: python numpy

如果更改numpy数组的视图,原始数组也会更改。这是预期的行为。

arr = np.array([1,2,3])
mask = np.array([True, False, False])
arr[mask] = 0
arr
# Out: array([0, 2, 3])

但是,如果我查看这样的视图并进行更改,那么原始数组不会更改:

arr = np.array([1,2,3])
mask_1 = np.array([True, False, False])
mask_1_arr = arr[mask_1]  # Becomes: array([1])
mask_2 = np.array([True])
mask_1_arr[mask_2] = 0
arr
# Out: array([1, 2, 3])

这对我来说意味着,当你看到一个视图时,你实际上得到了一个副本。它是否正确?这是为什么?

如果我使用数值索引的numpy数组而不是布尔值的numpy数组,则会出现相同的行为。 (例如arr[np.array([0])][np.array([0])] = 0不会将arr的第一个元素更改为0.)

1 个答案:

答案 0 :(得分:5)

basic slicing选择始终返回视图。按advanced indexing选择始终返回副本。 Selection by boolean mask是一种先进的形式 索引。 (另一种形式的高级索引是selection by integer array。)

但是,高级索引的赋值会影响原始数组。

所以

mask = np.array([True, False, False])
arr[mask] = 0

会影响arr,因为它是一项任务。相比之下,

mask_1_arr = arr[mask_1]

是通过布尔掩码选择的,因此mask_1_arrarr的一部分的副本。 一旦你有副本,夹具就会启动。当Python执行时

mask_2 = np.array([True])
mask_1_arr[mask_2] = 0

该作业会影响mask_1_arr,但由于mask_1_arr是副本, 它对arr没有影响。

|            | basic slicing    | advanced indexing |
|------------+------------------+-------------------|
| selection  | view             | copy              |
| assignment | affects original | affects original  |

在幕后,arr[mask] = something会导致Python调用 arr.__setitem__(mask, something)ndarray.__setitem__方法是 实施以修改arr。毕竟,这是人们应该期待的自然事物 __setitem__要做。

相反,表达式arr[indexer]会导致Python调用 arr.__getitem__(indexer)。当indexer是一个切片时,它的规律性 元素允许NumPy返回一个视图(通过修改步幅和偏移量)。何时indexer 通常是一个任意的布尔掩码或任意整数数组 没有规律选择的元素,所以没有办法返回一个 视图。因此必须返回副本。