Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Indexing tensor with binary matrix in numpy

I have a tensor A such that A.shape = (32, 19, 2) and a binary matrix B such that B.shape = (32, 19). Is there a one-line operation I can perform to get a matrix C, where C.shape = (32, 19) and C(i,j) = A[i, j, B[i,j]]?

Essentially, I want to use B as an indexing matrix, where if B[i,j] = 1 I take A[i,j,1] to form C(i,j).

like image 694
questionnaire Avatar asked Jul 18 '26 06:07

questionnaire


1 Answers

np.where to the rescue. It's the same principle as mtrw's answer:

In [344]: A=np.arange(4*3*2).reshape(4,3,2)

In [345]: B=np.zeros((4,3),dtype=int)

In [346]: B[[0,1,1,2,3],[0,0,1,2,2]]=1

In [347]: B
Out[347]: 
array([[1, 0, 0],
       [1, 1, 0],
       [0, 0, 1],
       [0, 0, 1]])

In [348]: np.where(B,A[:,:,1],A[:,:,0])
Out[348]: 
array([[ 1,  2,  4],
       [ 7,  9, 10],
       [12, 14, 17],
       [18, 20, 23]])

np.choose can be used if the last dimension is larger than 2 (but smaller than 32). (choose operates on a list or the 1st dimension, hence the rollaxis.

In [360]: np.choose(B,np.rollaxis(A,2))
Out[360]: 
array([[ 1,  2,  4],
       [ 7,  9, 10],
       [12, 14, 17],
       [18, 20, 23]])

B can also be used directly as an index. The trick is to specify the other dimensions in a way that broadcasts to the same shape.

In [373]: A[np.arange(A.shape[0])[:,None], np.arange(A.shape[1])[None,:], B]
Out[373]: 
array([[ 1,  2,  4],
       [ 7,  9, 10],
       [12, 14, 17],
       [18, 20, 23]])

This last approach can be modified to work when B does not match the 1st 2 dimensions of A.

np.ix_ may simplify this indexing

I, J = np.ix_(np.arange(4),np.arange(3))
A[I, J, B]
like image 107
hpaulj Avatar answered Jul 20 '26 21:07

hpaulj