Unexpected result when slicing an numpy array (view vs copy)

I am trying to reduce the number of copies in my code, and I came across unexpected behavior when working with numpy array slicing and views, as described in:

Scipy wiki page when copying numpy arrays

I came across the following behavior, which is unexpected for me:

Case 1 .:

import numpy as np a = np.ones((3,3)) b = a[:,1:2] b += 5 print a print b.base is a 

As expected, this produces:

 array([[ 1., 6., 1.], [ 1., 6., 1.], [ 1., 6., 1.]]) True 

Case 2: When performing slicing and adding on the same line, everything looks different:

 import numpy as np a = np.ones((3,3)) b = a[:,1:2] + 5 print a print b.base is a 

The part that surprises me is that [:, 1: 2] doesn't seem to create a view, which is then used as an argument to the left side, so it outputs:

 array([[ 1., 1., 1.], [ 1., 1., 1.], [ 1., 1., 1.]]) False 

Perhaps someone can shed light on why these two cases are different, I think something is missing.

Solution . I missed the obvious fact that the “+” operator, which is different from the in-place operator “+ =”, will always create a copy, so it is not actually connected, but it slices other than how the in-place operators are defined for numpy arrays.

To illustrate this, the following generates the same result as in case 2:

 import numpy as np a = np.ones((3,3)) b = a[:,1:2] b = b + 5 print a print b.base is a 
+4
source share
3 answers

The above does not differ from:

 >>> a=np.arange(5) >>> b=a >>> b array([0, 1, 2, 3, 4]) >>> b+=5 >>> a array([5, 6, 7, 8, 9]) >>> b array([5, 6, 7, 8, 9]) >>> b=b+5 >>> b array([10, 11, 12, 13, 14]) >>> a array([5, 6, 7, 8, 9]) 

Which, at least for me, seems to be the expected behavior. The b+=x operator calls __iadd__ , which first of all tries to change the array in place, so it will update b , which is still a kind of a . So far, the operator b=b+x calls __add__ , which creates new temporary data, and then assigns it b .

For a[i] +=b sequence (in numpy):

 a.__setitem__(i, a.__getitem__(i).__iadd__(b)) 
+3
source

a[:, 1:2] creates a view, but you do not change the view in the second example. Instead, + creates a new array from its arguments. Suppose you do

 a = np.ones((3, 3)) b = a + 5 

In this case, you do not expect a change to a , because this is not a complement in place. Operator + , not += . Same thing with the second example.

 b = a[:, 1:2] + 5 

does not change a[:, 1:2] , because it is not a complement in place.

+2
source

The default value when you need to slice a numpy array is to create b as a kind of a, so when b changes, the changes will also change, which is confirmed by your first case.

The second case is more complicated. You are not saying that b is a slice of a and then adding a number. What you do creates b as something that does not match a, so numpy forces you to copy data, not just create a view.

+1
source

Source: https://habr.com/ru/post/1496246/


All Articles