数组_2 = 数组_1 vs. 数组_2 = 数组_1.view()

4

这两者之间有什么区别:

array_2 = array_1
array_2 = array_1.view()

我希望有一个例子,演示在第一种情况下将 array_2 更改为 array 会在第二种情况下产生不同的结果。


1
我们通常不使用简单的 view()。更常见的是通过 reshape 或甚至 transpose 来创建一个 view。更重要的是要学习何时操作会产生 view 而不是 copy - hpaulj
阅读“view”文档,没有一个例子使用普通的“view()”。https://numpy.org/doc/stable/reference/generated/numpy.ndarray.view.html#numpy.ndarray.view - hpaulj
您的问题类似于最近的另一个问题,https://dev59.com/daz2oIgBc1ULPQZFivW6 - hpaulj
1个回答

7
理解的关键是,赋值永远不会复制或创建一个新对象。 赋值只是将相同的对象分配给一个新名称。 它为同一对象创建了一个“别名” - 相同事物的另一个名称。 视图创建一个新对象,它共享相同的基本缓冲区,即存储numpy数据的连续基本数组。 因此,对该数据的更改对使用该缓冲区的所有Python对象都可见。
请考虑以下示例:
>>> import numpy as np
>>> array = np.array([-3, -2, -1, 0, 1, 2, 3, 4], dtype=np.int64)
>>> array_view = array.view()
>>> array_alias = array
>>> array_alias is array
True
>>> array_view is array
False

所以,arrayarray_alias 是两个不同的名称,指向相同的 Python 对象,即我们在开始创建的 numpy.ndarray. arrayarray_view 是两个独立的 Python 对象。
如果我修改了这个对象,那么显然这两个指向同一对象的名称都将能够看到更改。
>>> array.dtype = np.uint64
>>> array
array([18446744073709551613, 18446744073709551614, 18446744073709551615,
                          0,                    1,                    2,
                          3,                    4], dtype=uint64)
>>> array_alias
array([18446744073709551613, 18446744073709551614, 18446744073709551615,
                          0,                    1,                    2,
                          3,                    4], dtype=uint64)

但是 视图不会

>>> array_view
array([-3, -2, -1,  0,  1,  2,  3,  4])

然而,如果我修改 数据 ,由于两个不同的对象(即原始数组和视图)引用相同的基础缓冲区,因此更改将对别名和视图可见:
>>> array
array([18446744073709551613, 18446744073709551614, 18446744073709551615,
                       1337,                    1,                    2,
                          3,                    4], dtype=uint64)
>>> array_alias
array([18446744073709551613, 18446744073709551614, 18446744073709551615,
                       1337,                    1,                    2,
                          3,                    4], dtype=uint64)
>>> array_view
array([  -3,   -2,   -1, 1337,    1,    2,    3,    4])

以下是另一个示例,使用切片(slice)操作创建numpy对象的视图:

>>> array = np.arange(16)
>>> array
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15])
>>> array_slice = array[::4]
>>> array_slice
array([ 0,  4,  8, 12])
>>> array is array_slice
False

我能够独立地操作这些对象:
>>> array_slice.shape = (2, 2)
>>> array_slice
array([[ 0,  4],
       [ 8, 12]])
>>> array
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15])

但是我无法独立操作他们的数据

>>> array_slice[:] = 1337
>>> array_slice
array([[1337, 1337],
       [1337, 1337]])
>>> array
array([1337,    1,    2,    3, 1337,    5,    6,    7, 1337,    9,   10,
         11, 1337,   13,   14,   15])

最后要注意的是,np.ndarray.view 方法通常在您想要创建一个 新对象 的情况下调用,这个新对象是原始数组的一个视图,但具有不同的 dtype,因此:

>>> array = np.array([-2, -1, 0, 1, 2], dtype=np.int64)
>>> bytewise = array.view(np.uint8)
>>> bytewise
array([254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
       255, 255, 255,   0,   0,   0,   0,   0,   0,   0,   0,   1,   0,
         0,   0,   0,   0,   0,   0,   2,   0,   0,   0,   0,   0,   0,
         0], dtype=uint8)

我们在现场修改视图形状,来查看64位有符号整数如何以原始字节(即8位整数)表示:

>>> bytewise.shape = array.shape[0], 8
>>> bytewise
array([[254, 255, 255, 255, 255, 255, 255, 255],
       [255, 255, 255, 255, 255, 255, 255, 255],
       [  0,   0,   0,   0,   0,   0,   0,   0],
       [  1,   0,   0,   0,   0,   0,   0,   0],
       [  2,   0,   0,   0,   0,   0,   0,   0]], dtype=uint8)
>>> array
array([-2, -1,  0,  1,  2])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接