I'm very puzzled by the following behaviour of NumPy when assigning elements to an array using an array as indices. Here is a minimal working example:
import numpy as np
i = np.arange(2,4)
a = np.arange(5)
a[:][i] = 0 # this modifies the a array
print(a)
b = np.arange(5)
b[i][:] = 0 # this does NOT modify the b array
print(b)
Why is the a
array modified and not the b
array? I suspect we are modifying a copy of the b
array, but I'm not sure how to show this explicitly. For example, id(a)
and id(a[:])
yield different results, yet a
is modified.
a[:]
is a view of a
, while a
and a[:]
are different python objects, they share the same underlying memory for the numpy data:
a2 = a[:]
a2.base is a # True
id(a2), id(a2.base), id(a) # (127331129255728, 127331129258032, 127331129258032)
However, b[i]
is a new array, independent from b
. b
and b[:]
each use a different space in memory to store the numpy data:
b2 = b[i]
b2.base # None
There is no good reason why you would need to chain [:][i]
or [i][:]
in numpy. Just remove the useless [:]
:
b[i] = 0
As explained in the documentation:
Views are created when elements can be addressed with offsets and strides in the original array. Hence, basic indexing always creates views. [...] Advanced indexing, on the other hand, always creates copies.
a[:] # view (basic indexing)
a[1:3] # view (basic indexing)
a[1:3][:] # view (basic indexing)
a[[2, 3]] # copy (advanced indexing)