Question about a array as another array index

Question:

I am confused about a operation of numpy, which using a matrix as index, like:

# a and b both are matrix:
a[b] = 0.0

The complete code are as following.

import numpy as np

a = np.mat('1 1; 1 2')

b = np.mat('0 0; 1 1')

print("a: ", a)
print("b: ", b)

a[~b] = 0.0

print("a: ", a)

And I get result are as following, but I don’t know why.

a:  
[[1 1]
 [1 2]]
b:  
[[0 0]
 [1 1]]
a:  
[[0 0]
 [0 0]]
Asked By: lmixq lin

||

Answers:

The ~ is not something we use much with numpy – so lets check that by itself:

In [184]: ~b
Out[184]: 
matrix([[-1, -1],
        [-2, -2]], dtype=int32)

Negative indices "count" from the end.

In [185]: a[~b]
Out[185]: 
matrix([[[1, 2],         
         [1, 2]],

        [[1, 1],         
         [1, 1]]])

In [186]: a[~b].shape
Out[186]: (2, 2, 2)

This result puzzles me, because np.matrix is supposed to restricted to 2d.

We are trying to discourage the use of np.matrix, but if I convert a and b to ndarray, the results are the same:

In [189]: a = np.mat('1 1; 1 2').A 
     ...: b = np.mat('0 0; 1 1').A

In [192]: a[~b]
Out[192]: 
array([[[1, 2],
        [1, 2]],

       [[1, 1],
        [1, 1]]])

indexing with an array, acts just on one dimension, here the first; so it’s using a (2,2) array to index the first dimension of a, resulting in a (2,2,2). This action would be clearer if the dimensions weren’t all 2.

In [197]: a[~b, :]
Out[197]: 
array([[[1, 2],      # index is [-1,-1], the last row
        [1, 2]],

       [[1, 1],      # index is [-2,-2], the 2nd to last row (first)
        [1, 1]]])

Since this indexing selects both rows, when used as a setter, both rows are set to 0. So this is puzzling largely because ~b produces a numeric index array.

I wonder if instead, this code was meant to do boolean array indexing.

In [203]: b.astype(bool)
Out[203]: 
array([[False, False],
       [ True,  True]])

Now ~ is a logical not:

In [204]: ~(b.astype(bool))
Out[204]: 
array([[ True,  True],
       [False, False]])

Indexing with a boolean that matches in shape, selects/or/not on an element by element basis:

In [205]: a[~(b.astype(bool))]
Out[205]: array([1, 1])

In [206]: a[(b.astype(bool))]
Out[206]: array([1, 2])

Now the the 0 assignment just sets the first row.

In [207]: a[~(b.astype(bool))]=0

In [208]: a
Out[208]: 
array([[0, 0],
       [1, 2]])  

The boolean array indexing would be clear with this example:

In [211]: b = np.array([[0,1],[1,0]], bool)
In [212]: b
Out[212]: 
array([[False,  True],
       [ True, False]])

In [213]: a = np.arange(1,5).reshape(2,2); a
Out[213]: 
array([[1, 2],
       [3, 4]])

In [214]: a[b]             # select the opposite corners
Out[214]: array([2, 3])
In [215]: a[~b]            # select the diagonal
Out[215]: array([1, 4])
Answered By: hpaulj
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.