1

I'm running into this problem over and over again, and can't seem to find a clean solution for this. So I'm trying to index an array with another array. I have a 2d numpy array. And a 1d numpy array with the same length as the 1st dimension of the 2d array I'm trying to index and the elements represent the indices of the columns I try to extract:

import numpy as np

A = np.random.rand((5,3))

B = np.asarray([2,1,2,0,1])

The behaviour that I want is extracting for all rows the corresponding column in array B. This could be done by

C = A[np.arange(A.shape[0]),B]

But I can imagine that there is a better way to get this behaviour. Using a : as indexing the first row gives the wrong behaviour.

If there is a cleaner way of doing this that would be great. I'm really used to this array indexing from Matlab, but maybe there is no equivalent in numpy. Using boolean indices is of course an option, but that also requires converting arrays all the time.

4
  • Wrap that A[np.arange(A.shape[0]),B] in a function and call it really_clean_solution()? Commented Dec 5, 2017 at 12:26
  • How would you write this in MATLAB? MATLAB handling of pairwise vs. block indexing is different. Commented Dec 5, 2017 at 16:03
  • A non-sarcastic variant of @Divakar's: def rl_(I): return np.arange(I.size) rl standing for range_like. A[rl_(B), B] is not that bad, is it? Commented Dec 6, 2017 at 1:11
  • Seriously, what is the cleaner way of doing this in MATLAB? I must be out of date with that language, but I can't find it. Commented Dec 6, 2017 at 5:11

2 Answers 2

2

I think what you look after is np.choose(B,A.T) :

In [125]: A
Out[125]: 
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6,  7,  8],
       [ 9, 10, 11],
       [12, 13, 14]])

In [126]: B = np.asarray([2,1,2,0,1])

In [127]: np.choose(B,A.T)
Out[127]: array([ 2,  4,  8,  9, 13])
Sign up to request clarification or add additional context in comments.

3 Comments

I wouldn't recommend that. Try A = np.zeros((2, 32)), B = np.zeros((2,), int).
choose has a max size of 32
np.choose documentation discourages this use, see the note, "choices should neither be, nor be thought of as, a single array, i.e., the outermost sequence-like container should be either a list or a tuple."
0
In [60]: A = np.arange(1,16).reshape(5,3)
In [61]: B = np.array([2,1,2,0,1])
In [62]: C = A[np.arange(A.shape[0]),B]
In [63]: C
Out[63]: array([ 3,  5,  9, 10, 14])

In Octave

>>  A = reshape(1:15, 3,5).';
>> B = [3,2,3,1,2];
>> A
A =

    1    2    3
    4    5    6
    7    8    9
   10   11   12
   13   14   15

>> A(:,B)
ans =

    3    2    3    1    2
    6    5    6    4    5
    9    8    9    7    8
   12   11   12   10   11
   15   14   15   13   14

This is the same as numpy:

In [65]: A[:,B]
Out[65]: 
array([[ 3,  2,  3,  1,  2],
       [ 6,  5,  6,  4,  5],
       [ 9,  8,  9,  7,  8],
       [12, 11, 12, 10, 11],
       [15, 14, 15, 13, 14]])

You imply that there's something clean for indexing one item from each column in MATLAB/Octave, but I missing it. I used to work a lot in that language, but I've gotten out of practice.

sub2ind does the job:

>> sub2ind([3,5],B, 1:5)
ans =

    3    5    9   10   14

>> A.'(:)(sub2ind([3,5],B,1:5))
ans =

    3
    5
    9
   10
   14

(The 'F' vs 'C' ordering is complicating my comparison)

numpy has a similar ravel_multi_index:

In [69]: np.ravel_multi_index((np.arange(5),B),(5,3))
Out[69]: array([ 2,  4,  8,  9, 13], dtype=int32)
In [71]: A.flat[_]
Out[71]: array([ 3,  5,  9, 10, 14])

Comments

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.