We index on the first axis of the input array with these indices. To get 2D
output, we just need to rearrange the axes and then change them. So the approach would be with np.transpose
/ np.swapaxes
and np.reshape
, so -
mats[idxs].swapaxes(1,2).reshape(-1,mats.shape[-1]*idxs.shape[-1])
Run Example -
In [83]: mats Out[83]: array([[[1, 1], [7, 1]], [[6, 6], [5, 8]], [[7, 1], [6, 0]], [[2, 7], [0, 4]]]) In [84]: idxs Out[84]: array([[2, 3], [0, 3], [1, 2]]) In [85]: mats[idxs].swapaxes(1,2).reshape(-1,mats.shape[-1]*idxs.shape[-1]) Out[85]: array([[7, 1, 2, 7], [6, 0, 0, 4], [1, 1, 2, 7], [7, 1, 0, 4], [6, 6, 7, 1], [5, 8, 6, 0]])
Performance improvement with np.take
for repeated indexes
With repeating metrics, for performance, we better use np.take
by indexing on axis=0
. Let both of these approaches and the times when idxs
have many duplicate indexes be listed.
Function Definitions -
def simply_indexing_based(mats, idxs): ncols = mats.shape[-1]*idxs.shape[-1] return mats[idxs].swapaxes(1,2).reshape(-1,ncols) def take_based(mats, idxs):np.take(mats,idxs,axis=0) ncols = mats.shape[-1]*idxs.shape[-1] return np.take(mats,idxs,axis=0).swapaxes(1,2).reshape(-1,ncols)
Runtime Test -
In [156]: mats = np.random.randint(0,9,(10,2,2)) In [157]: idxs = np.random.randint(0,10,(1000,1000))
Thus, we see a general improvement of 1.5x+
.
To get an idea of ββthe improvement with np.take
, let time be only part of the indexing -
In [168]: %timeit mats[idxs] 10 loops, best of 3: 22.8 ms per loop In [169]: %timeit np.take(mats,idxs,axis=0) 100 loops, best of 3: 8.88 ms per loop
For this data its 2.5x+
. Not bad!