pythonarraysnumpyindexing

How do element assignments work with numpy arrays using an array for indexing?


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.


Solution

  • 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
    

    When is a view created?

    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)