Reputation: 2645
Given an array and a mask, we can assign new values to the positions that are TRUE in the mask:
import numpy as np
a = np.array([1,2,3,4,5,6])
mask1 = (a==2) | (a==5)
a[mask1] = 100
print a
# [ 1 100 3 4 100 6]
However, if we apply a second mask over the first one, we can access to the values but we cannot modify them:
a = np.array([1,2,3,4,5,6])
mask1 = (a==2) | (a==5)
mask2 = (a[mask1]==2)
print a[mask1][mask2]
# [2]
a[mask1][mask2] = 100
print a
# [ 1 2 3 4 5 6 ]
Why does it happen?
(Even if it seems a bizarre way to do this. Just out of curiosity)
Upvotes: 4
Views: 358
Reputation: 176840
You are chaining advanced* indexing operations for the assignment, which prevents the value 100 being written back to the original array.
a[mask1]
returns a new array with a copy of the original data. Writing a[mask1][mask2] = 100
means that this new array is indexed with mask2
and the value 100 assigned to it. This leaves a
unchanged.
Simply viewing the items will appear to work fine because the values you pick out from the copy a[mask1]
are the values you would want from the original array (although this is still inefficient as data is copied multiple times).
*advanced (or "fancy") indexing is triggered with a boolean array or an array of indices. It always returns a new array, unlike basic indexing which returns a view onto the original data (this is triggered, for example, by slicing).
Upvotes: 3
Reputation: 476709
This is probably because you mix getters and setters preventing backpropagation.
It's because you use mark1
as an indexer:
>>> mask1
array([False, True, False, False, True, False], dtype=bool)
now by setting a[mask1] = 100
, you will set all the elements where mask1
was true thus resulting in
>>> a
array([ 1, 100, 3, 4, 100, 6])
note that you have only called a "setter" so to speak on a
.
Now for a[mask1][mask2] = 100
you actually call both a getter and setter. Indeed you can write this as:
temp = a[mask1] #getter
temp[mask2] = 2#setter
as a result you only set the value in the temp
, and thus the value is not "backpropagated" so to speak to a
itself. You should see temp
as a copy (although internally it is definitely possible that a python interpreter handles it differently).
Note: note that there can be circumstances where this behavior works: if temp
is for instance a view on an array, it could support backwards propagation. This page for instance shows ways to return a view instead of a copy.
Upvotes: 3