2

I'm quite new to Python. I was reading and testing codes in the Numpy official documentation. At the end of part 2.6.2 (Indexing with Boolean Arrays) there's an example that returns a weird answer. Funny though, the documentation says " a weird thing to do".

a = np.arange(12).reshape(3, 4)
b1 = np.array([False, True, True])
b2 = np.array([True, False, True, False])
a[b1, b2]

I think it should return the following answer (or sth like that):

array([ 4, 6, 8, 10])

but it returns:

array([ 4, 10])

here is a logic map. Am I wrong somehow? Logic Map

  • Can you provide a link to the exact numpy documentation you're looking at so people can find the relevant section? – ljdyer Aug 29 '22 at 07:51
  • So what DOES it output? I only get errors. – klutt Aug 29 '22 at 07:55
  • what's the weird answer? – hpaulj Aug 29 '22 at 08:00
  • I have downloaded the pdf version from https://numpy.org/doc/stable/numpy-user.pdf , page 23 – Hesam Jokar Aug 29 '22 at 08:01
  • It does not return anything. Please correct your code. – klutt Aug 29 '22 at 08:04
  • 1
    @HesamJokar - I can't find a corresponding example in the official [documentation](https://numpy.org/devdocs/user/basics.indexing.html#boolean-array-indexing) or an explicit explanation for this behavior `a[np.flatnonzero(b1), np.flatnonzero(b2)]` instead of the expectable `a[np.ix_(b1, b2)]`. I think this is a relevant question. – Michael Szczesny Aug 29 '22 at 08:45
  • it's the 'diagonal' of what you expect, `a[[1,2],[0,2]]`. – hpaulj Aug 29 '22 at 09:13
  • @MichaelSzczesny As you mentioned, this example is not included in the web version. But, ironically, it returns this false answer. Thanks – Hesam Jokar Aug 29 '22 at 10:35

1 Answers1

1

As the docs pointed out, it is a weird thing to do.

In practice, you would use different methods for each of the results that you want.

(see below)

As @Michael pointed out in the comments, passing two boolean arrays converts them into index numbers first:

a[b1, b2]

 |
 V

a[np.flatnonzero(b1), np.flatnonzero(b2)]

 |
 V

a[(array([1, 2]), array([0, 2]))]

Perhaps it is implemented this way (and not like a[np.ix_(b1, b2)]) by the analogy of having only one array for indexing. For example, when you simply do a[b1], this might be happening internally: a[np.flatnonzero(b1)].

And for more than 1 array this is simply the same mechanic.


1. To get your expected output:

See this answer. In your case it would be:

a[b1][:, b2]

produces

array([[ 4,  6],
       [ 8, 10]])

which you can then .flatten():

array([ 4,  6,  8, 10])

Or:

You can use np.ix_:

np.ix_(b1, b2) produces a tuple of arrays:

(array([[1],
        [2]]),
 array([[0, 2]]))

which can be used to get the same result:

a[np.ix_(b1, b2)].flatten()

2. To get array([ 4, 10]) in a non-weird way:

Use integer array indexing explicitly:

a[[1, 2], [0, 2]]
Vladimir Fokow
  • 3,728
  • 2
  • 5
  • 27
  • Thank you. Now the returned array seems right. However, the included example remains Weird. Thank you for the response. – Hesam Jokar Aug 29 '22 at 10:39
  • @HesamJokar, in my last example numpy iterates over the corresponding pairs: (1, 0), then (2,2) - thus only 2 elements are selected. This is how integer array indexing works in numpy – Vladimir Fokow Aug 29 '22 at 10:40
  • Thanks. Unlike Matlab, it derives X from only the first pair and Y from the second, like the Boolean indexing example. It's odd, but I'm getting used to it. Thanks for the note. – Hesam Jokar Aug 29 '22 at 11:04
  • 1
    MATLAB makes selecting the block easy. The diagonal is harder. In `numpy` it's the diagonal that's easy. `ix_` (or equivalent) is needed to get the block, The docs should make it clear that numpy uses `broadcasting` to pair elements of indexing arrays. – hpaulj Aug 29 '22 at 14:58