视图和numpy数组的浅表副本有什么区别? [英] What's the difference between a view and a shallow copy of a numpy array?

查看:132
本文介绍了视图和numpy数组的浅表副本有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在NumPy中,我知道切片数组会为您提供视图",在我看来,这与浅表副本完全相同.它们有什么不同?

解决方案

与Python列表对象包含对元素对象第一级的引用(后者可能引用更深层次的对象)不同,NumPy数组仅引用a单个数据缓冲区,用于存储数组所有维度的所有元素值,并且该数据缓冲区之外没有元素对象的层次结构.

列表的浅表副本将包含元素引用的第一级副本,并与原始列表共享所引用的元素对象. NumPy数组的浅表副本应该包含什么不太明显. ( A )应该与原始共享数据缓冲区,还是( B )拥有自己的副本(有效地使其成为深层副本)?

NumPy数组的 view 是意义A上的浅表副本,即它引用与原始数组相同的数据缓冲区,因此对原始数据的更改会影响视图数据,反之亦然. /p>

库函数 copy.copy()应该创建其参数的浅表副本,但是当将其应用于NumPy数组时,它将在意义B上创建浅表副本,即新数组它自己的数据缓冲区副本,因此对一个数组的更改不会影响另一个数组.

以下代码显示了复制/查看NumPy数组的不同方法:

import numpy as np
import copy

x = np.array([10, 11, 12, 13])

# Create views of x (shallow copies sharing data) in 2 different ways
x_view1 = x.view()
x_view2 = x[:]          # Creates a view using a slice

# Create full copies of x (not sharing data) in 2 different ways
x_copy1 = x.copy()
x_copy2 = copy.copy(x)  # Calls x.__copy__() which creates a full copy of x

# Change some array elements to see what happens
x[0]       = 555        # Affects x, x_view1, and x_view2
x_view1[1] = 666        # Affects x, x_view1, and x_view2
x_view2[2] = 777        # Affects x, x_view1, and x_view2
x_copy1[0] = 888        # Affects only x_copy1
x_copy2[0] = 999        # Affects only x_copy2

print(x)                # [555 666 777  13]
print(x_view1)          # [555 666 777  13]
print(x_view2)          # [555 666 777  13]
print(x_copy1)          # [888  11  12  13]
print(x_copy2)          # [999  11  12  13]

上面的示例创建了整个原始数组索引范围的视图,并具有与原始数组相同的数组属性,这并不是很有趣(可以用简单的别名替换,例如x_alias = x).使视图强大的原因在于它们可以是原始文档的选定部分的视图,并且具有不同的属性.在扩展上述示例的以下几行代码中对此进行了演示:

x_view3 = x[::2].reshape(2,1) # Creates a reshaped view of every 2nd element of x
print(x_view3)          # [[555]
                        #  [777]]
x_view3[1] = 333        # Affects 2nd element of x_view3 and 3rd element of x
print(x)                # [555 666 333  13]
print(x_view3)          # [[555]
                        #  [333]]

In NumPy, I understand that slicing an array gives you a "view", which seems to me the exact same as a shallow copy. How are they different?

解决方案

Unlike a Python list object which contains references to the first level of element objects (which in turn may reference deeper levels of objects), a NumPy array references only a single data buffer which stores all the element values for all the dimensions of the array, and there is no hierarchy of element objects beyond this data buffer.

A shallow copy of a list would contain copies of the first level of element references, and share the referenced element objects with the original list. It is less obvious what a shallow copy of a NumPy array should contain. Should it (A) share the data buffer with the original, or (B) have its own copy (which effectively makes it a deep copy)?

A view of a NumPy array is a shallow copy in sense A, i.e. it references the same data buffer as the original, so changes to the original data affect the view data and vice versa.

The library function copy.copy() is supposed to create a shallow copy of its argument, but when applied to a NumPy array it creates a shallow copy in sense B, i.e. the new array gets its own copy of the data buffer, so changes to one array do not affect the other.

Here's some code showing different ways to copy/view NumPy arrays:

import numpy as np
import copy

x = np.array([10, 11, 12, 13])

# Create views of x (shallow copies sharing data) in 2 different ways
x_view1 = x.view()
x_view2 = x[:]          # Creates a view using a slice

# Create full copies of x (not sharing data) in 2 different ways
x_copy1 = x.copy()
x_copy2 = copy.copy(x)  # Calls x.__copy__() which creates a full copy of x

# Change some array elements to see what happens
x[0]       = 555        # Affects x, x_view1, and x_view2
x_view1[1] = 666        # Affects x, x_view1, and x_view2
x_view2[2] = 777        # Affects x, x_view1, and x_view2
x_copy1[0] = 888        # Affects only x_copy1
x_copy2[0] = 999        # Affects only x_copy2

print(x)                # [555 666 777  13]
print(x_view1)          # [555 666 777  13]
print(x_view2)          # [555 666 777  13]
print(x_copy1)          # [888  11  12  13]
print(x_copy2)          # [999  11  12  13]

The above example creates views of the entire original array index range and with the same array attributes as the original, which is not very interesting (could be replaced with a simple alias, e.g. x_alias = x). What makes views powerful is that they can be views of chosen parts of the original, and have different attributes. This is demonstrated in the next few lines of code which extend the above example:

x_view3 = x[::2].reshape(2,1) # Creates a reshaped view of every 2nd element of x
print(x_view3)          # [[555]
                        #  [777]]
x_view3[1] = 333        # Affects 2nd element of x_view3 and 3rd element of x
print(x)                # [555 666 333  13]
print(x_view3)          # [[555]
                        #  [333]]

这篇关于视图和numpy数组的浅表副本有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆