27

Suppose I have a matrix A with some arbitrary values:

array([[ 2, 4, 5, 3],
       [ 1, 6, 8, 9],
       [ 8, 7, 0, 2]])

And a matrix B which contains indices of elements in A:

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

How do I select values from A pointed by B, i.e.:

A[B] = [[2, 2, 4, 5],
        [1, 9, 8, 6],
        [2, 0, 7, 8]]

3 Answers 3

26

EDIT: np.take_along_axis is a builtin function for this use case implemented since numpy 1.15. See @hpaulj 's answer below for how to use it.


You can use NumPy's advanced indexing -

A[np.arange(A.shape[0])[:,None],B]

One can also use linear indexing -

m,n = A.shape
out = np.take(A,B + n*np.arange(m)[:,None])

Sample run -

In [40]: A
Out[40]: 
array([[2, 4, 5, 3],
       [1, 6, 8, 9],
       [8, 7, 0, 2]])

In [41]: B
Out[41]: 
array([[0, 0, 1, 2],
       [0, 3, 2, 1],
       [3, 2, 1, 0]])

In [42]: A[np.arange(A.shape[0])[:,None],B]
Out[42]: 
array([[2, 2, 4, 5],
       [1, 9, 8, 6],
       [2, 0, 7, 8]])

In [43]: m,n = A.shape

In [44]: np.take(A,B + n*np.arange(m)[:,None])
Out[44]: 
array([[2, 2, 4, 5],
       [1, 9, 8, 6],
       [2, 0, 7, 8]])
Sign up to request clarification or add additional context in comments.

3 Comments

I don't get how these work... could you add some explanations?
@JasonS Basically using a range array along first axis to select one per along that axis for each element in B. The provided link should give all the details needed.
Hmm... well, that's fine but I look at the advanced indexing link and it doesn't make sense to me. I need to extend your example to an N-dimensional array where only the last index is applied, and I'm not sure how to do it.
7

More recent versions have added a take_along_axis function that does the job:

A = np.array([[ 2, 4, 5, 3], 
              [ 1, 6, 8, 9], 
              [ 8, 7, 0, 2]])  
                                          
B = np.array([[0, 0, 1, 2], 
              [0, 3, 2, 1], 
              [3, 2, 1, 0]])     
                                        
np.take_along_axis(A, B, 1)  
                                       
Out[]: 
array([[2, 2, 4, 5],
       [1, 9, 8, 6],
       [2, 0, 7, 8]])

There's also a put_along_axis.

Comments

5

I know this is an old question, but another way of doing it using indices is:

A[np.indices(B.shape)[0], B]

output:

[[2 2 4 5]
 [1 9 8 6]
 [2 0 7 8]]

1 Comment

Very elegant way of doing it!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.