如果更改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.)
答案 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_arr
是arr
的一部分的副本。
一旦你有副本,夹具就会启动。当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
通常是一个任意的布尔掩码或任意整数数组
没有规律选择的元素,所以没有办法返回一个
视图。因此必须返回副本。