# Indexing one array by another in numpy

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]]
``````

47

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)[:,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 : A
Out:
array([[2, 4, 5, 3],
[1, 6, 8, 9],
[8, 7, 0, 2]])

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

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

In : m,n = A.shape

In : np.take(A,B + n*np.arange(m)[:,None])
Out:
array([[2, 2, 4, 5],
[1, 9, 8, 6],
[2, 0, 7, 8]])
``````
Tuesday, June 1, 2021

21

`numpy.bincount` was introduced for this purpose:

``````tmp = np.bincount(idx, w)
v[:len(tmp)] += tmp
``````

I think as of 1.6 you can also pass a minlength to `bincount`.

Sunday, August 15, 2021

70

there is not [yet] a version of numpy that has been ported to Python 3.

the last update I heard from the people on the project was this: http://blog.jarrodmillman.com/2009/01/when-will-numpy-and-scipy-migrate-to.html

for now, if you need Numpy, you are stuck with Python 2.x

Saturday, September 25, 2021

74

I think you can use Morphology functions in `scipy.ndimage`, here is an example:

``````import pylab as pl
import numpy as np
from scipy import ndimage
img2 = ndimage.binary_erosion(img, iterations=40)
img3 = ndimage.binary_dilation(img2, iterations=40)
labels, n = ndimage.label(img3)
counts = np.bincount(labels.ravel())
counts = 0
img4 = labels==np.argmax(counts)
img5 = ndimage.binary_fill_holes(img4)
result = ~img & img5
result = ndimage.binary_erosion(result, iterations=3)
result = ndimage.binary_dilation(result, iterations=3)
pl.imshow(result, cmap="gray")
``````

the output is: Sunday, October 24, 2021

31

Since `x` is `float`. I would do this:

``````In :

np.array([(x[y==0]==np.unique(x)[..., np.newaxis]).sum(axis=1),
(x[y==1]==np.unique(x)[..., np.newaxis]).sum(axis=1)]).T
Out:
array([[2, 1],
[2, 1],
[0, 1],
[1, 1],
[0, 1]])
``````

Speed:

``````In :

%%timeit
ux=np.unique(x)[..., np.newaxis]
np.array([(x[y==0]==ux).sum(axis=1),
(x[y==1]==ux).sum(axis=1)]).T
10000 loops, best of 3: 92.7 µs per loop
``````

Solution @seikichi

``````In :

%%timeit
>>> x = np.array([1.1, 1.1, 1.1, 3.3, 2.2, 2.2, 2.2, 5.5, 4.4, 4.4])
>>> y = np.array([0, 1, 0, 1, 0, 1, 0, 1, 0, 1])
>>> r = np.r_[np.unique(x), np.inf]
>>> np.concatenate([[np.histogram(x[y == v], r)] for v in sorted(set(y))]).T
1000 loops, best of 3: 388 µs per loop
``````

For more general cases when `y` is not just `{0,1}`, as @askewchan pointed out:

``````In :

%%timeit
ux=np.unique(x)[..., np.newaxis]
uy=np.unique(y)
np.asanyarray([(x[y==v]==ux).sum(axis=1) for v in uy]).T
10000 loops, best of 3: 116 µs per loop
``````

To explain the broadcasting further, see this example:

``````In :

np.unique(a)
Out:
array([ 0. ,  0.2,  0.4,  0.5,  0.6,  1.1,  1.5,  1.6,  1.7,  2. ])
In :

np.unique(a)[...,np.newaxis] #what [..., np.newaxis] will do:
Out:
array([[ 0. ],
[ 0.2],
[ 0.4],
[ 0.5],
[ 0.6],
[ 1.1],
[ 1.5],
[ 1.6],
[ 1.7],
[ 2. ]])
In :

(a==np.unique(a)[...,np.newaxis]).astype('int') #then we can boardcast (converted to int for readability)
Out:
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0]])
In :

(a==np.unique(a)[...,np.newaxis]).sum(axis=1) #getting the count of unique value becomes summing among the 2nd axis
Out:
array([1, 3, 1, 1, 2, 1, 1, 1, 1, 3])
``````
Monday, November 22, 2021