Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between a view and a shallow copy of a numpy array?

Tags:

python

copy

numpy

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?

like image 507
Eric Auld Avatar asked Jan 29 '23 00:01

Eric Auld


2 Answers

Basically there are two main types one is shallow copy and second is deep copy.

Shallow copy: In case shallow copy if you change value in one variable it will reflect a change into other variable. for example :

import numpy as np
a = np.array([1,2,3,4])
b=a
b[0]=353
print(b)
#>>> array([353,2,3,4])
print(a)
#>>> array([353,2,3,4])

Deep copy: In case Deep copy if you change value in one variable it will not reflect a change into other variable. for example :

import numpy as np
a = np.array([1,2,3,4])
c=np.copy(a)
c[0]=111
print(c)
#>>> array([111,2,3,4])
print(a)
#>>> array([1,2,3,4])
like image 37
Sachin Chaurasiya Avatar answered Jan 30 '23 15:01

Sachin Chaurasiya


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]]
like image 84
Ovaflo Avatar answered Jan 30 '23 15:01

Ovaflo