【问题标题】:View of a view of a numpy array is a copy?numpy数组视图的视图是副本吗?
【发布时间】:2016-12-10 15:56:04
【问题描述】:

如果您更改 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。)

【问题讨论】:

    标签: python numpy


    【解决方案1】:

    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 是任意布尔掩码或任意整数数组,一般有 所选元素没有规律性,因此无法返回 看法。因此必须返回一份副本。

    【讨论】:

    • 这一切都说得通!我想那时没有简单的方法来做一个像arr[x][y] = 1 这样的单行。现在我通过分配一个中间值来做到这一点,例如int = arr[x]; int[y] = 1; arr[x] = int.
    • 如果x 是一个布尔掩码,则单行等效项将是np.put(arr, np.flatnonzero(x)[y], 1)np.flatnonzero(x) 将布尔掩码转换为一维整数数组。然后,您可以使用np.flatnonzero(x)[y] 选择这些整数的一些子集,其中y 可以是基本切片或高级索引器。然后np.put(arr, np.flatnonzero(x)[y], 1) 工作,因为它大致相当于arr.flat[np.flatnonzero(x)[y]] = 1
    • 如果arr 是一维的,arr[np.flatnonzero(x)[y]] = 1 也可以。上面np.put 的目的是提供一个即使arr 是n 维也有效的答案。
    猜你喜欢
    • 1970-01-01
    • 2012-07-16
    • 2018-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多