Numpy Indexing: Broadcasting With Boolean Arrays
Solution 1:
As @Divakarnoted in comments, Boolean advanced indices behave as if they were first fed through np.nonzero
and then broadcast together, see the relevant documentation for extensive explanations. To quote the docs,
In general if an index includes a Boolean array, the result will be identical to inserting
obj.nonzero()
into the same position and using the integer array indexing mechanism described above.x[ind_1, boolean_array, ind_2]
is equivalent tox[(ind_1,) + boolean_array.nonzero() + (ind_2,)]
. [...] Combining multiple Boolean indexing arrays or a Boolean with an integer indexing array can best be understood with theobj.nonzero()
analogy. The functionix_
also supports boolean arrays and will work without any surprises.
In your case broadcasting would not necessarily be a problem, since both arrays have only two nonzero elements. The problem is the number of dimensions in the result:
>>>len(b1[:,None].nonzero())
2
>>>len(b2.nonzero())
1
Consequently the indexing expression a[b1[:,None], b2]
would be equivalent to a[b1[:,None].nonzero() + b2.nonzero()]
, which would put a length-3 tuple inside a
, corresponding to a 3d array index. Hence the error you see about "too many indices".
The surprises mentioned in the docs are very close to your example: what if you hadn't injected that singleton dimension? Starting from a length-3 and a length-4 Boolean array you would've ended up with a length-2 advanced index, i.e. a 1d array of size (2,)
. This is never what you'd want, which is leads us to another piece of trivia in the subject.
There's been a lot of discussion in planning to revamp advanced indexing, see the work-in-progress draft NEP 21. The gist of the issue is that fancy indexing in numpy, while clearly documented, has some very quirky features which aren't practically useful for anything, but which can bite you if you make a mistake by producing surprising results rather than errors.
A relevant quote from the NEP:
Mixed cases involving multiple array indices are also surprising, and only less problematic because the current behavior is so useless that it is rarely encountered in practice. When a boolean array index is mixed with another boolean or integer array, boolean array is converted to integer array indices (equivalent to
np.nonzero()
) and then broadcast. For example, indexing a 2D array of size(2, 2)
likex[[True, False], [True, False]]
produces a 1D vector with shape(1,)
, not a 2D sub-matrix with shape(1, 1)
.
Now, I emphasize that the NEP is very much work-in-progress, but one of the suggestions in the current state of the NEP is to forbid Boolean arrays in advanced indexing cases such as the above, and only allow them in "outer indexing" scenarios, i.e. exactly what np.ix_
would help you do with your Boolean array:
Boolean indexing is conceptionally outer indexing. Broadcasting together with other advanced indices in the manner of legacy indexing [i.e. the current behaviour] is generally not helpful or well defined. A user who wishes the "nonzero" plus broadcast behaviour can thus be expected to do this manually.
My point is that the behaviour of Boolean advanced indices and their deprecation status (or lack thereof) may change in the not-so-distant future.
Post a Comment for "Numpy Indexing: Broadcasting With Boolean Arrays"