如果更改numpy数组的视图,则原始数组也会更改。这是预期的行为。
arr = np.array([1,2,3])
mask = np.array([True, False, False])
arr[mask] = 0
arr
# Out: array([0, 2, 3])
Run Code Online (Sandbox Code Playgroud)
但是,如果我对这种视图进行更改,然后更改,则原始数组不会更改:
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])
Run Code Online (Sandbox Code Playgroud)
对我而言,这意味着,当您查看某个视图时,您实际上会获得一份副本。它是否正确?为什么是这样?
如果我使用数字索引的numpy数组而不是布尔值的numpy数组,则会发生相同的行为。(例如arr[np.array([0])][np.array([0])] = 0,不会将第一个元素更改arr为0。)
通过基本切片进行选择总是返回一个视图。通过高级索引进行选择始终会返回一个副本。 通过布尔掩码进行选择是高级索引的一种形式。(高级索引的另一种形式是通过整数数组进行选择。)
但是,通过高级索引分配会影响原始数组。
所以
mask = np.array([True, False, False])
arr[mask] = 0
Run Code Online (Sandbox Code Playgroud)
影响,arr因为它是一项任务。相反,
mask_1_arr = arr[mask_1]
Run Code Online (Sandbox Code Playgroud)
是通过布尔掩码选择的,所以mask_1_arr是的一部分的副本arr。拥有副本后,夹具就到了。Python执行时
mask_2 = np.array([True])
mask_1_arr[mask_2] = 0
Run Code Online (Sandbox Code Playgroud)
分配会影响mask_1_arr,但由于mask_1_arr是副本,因此对无效arr。
| | basic slicing | advanced indexing |
|------------+------------------+-------------------|
| selection | view | copy |
| assignment | affects original | affects original |
Run Code Online (Sandbox Code Playgroud)
在后台,arr[mask] = something使Python调用
arr.__setitem__(mask, something)。ndarray.__setitem__实现该方法进行修改arr。毕竟,这是人们应该__setitem__做的自然的事情
。
相反,作为表达式arr[indexer]导致Python调用
arr.__getitem__(indexer)。当indexer是切片时,元素的规则性允许NumPy返回视图(通过修改步幅和偏移量)。当indexer
为任意布尔掩码或任意整数数组时,所选元素通常没有规律性,因此无法返回视图。因此,必须返回副本。
| 归档时间: |
|
| 查看次数: |
158 次 |
| 最近记录: |