Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use 2D matrix as indexes for a 3D matrix in numpy?

Say I have an array of shape 2x3x3, which is a 3D matrix. I also have a 2D matrix of shape 3x3 that I would like to use as indices for the 3D matrix along the first axis. Example is below.

Example run:

>>> np.random.randint(0,2,(3,3)) # index
array([[0, 1, 0],
       [1, 0, 1],
       [1, 0, 0]])

>> np.random.randint(0,9,(2,3,3)) # 3D matrix
array([[[4, 4, 5],
        [2, 6, 7],
        [2, 6, 2]],

       [[4, 0, 0],
        [2, 7, 4],
        [4, 4, 0]]])
>>> np.array([[4,0,5],[2,6,4],[4,6,2]]) # result
array([[4, 0, 5],
       [2, 6, 4],
       [4, 6, 2]])
like image 458
Matthew Mage Avatar asked Jul 26 '17 19:07

Matthew Mage


3 Answers

It seems you are using 2D array as index array and 3D array to select values. Thus, you could use NumPy's advanced-indexing -

# a : 2D array of indices, b : 3D array from where values are to be picked up
m,n = a.shape
I,J = np.ogrid[:m,:n]
out = b[a, I, J] # or b[a, np.arange(m)[:,None],np.arange(n)]

If you meant to use a to index into the last axis instead, just move a there : b[I, J, a].

Sample run -

>>> np.random.seed(1234)
>>> a = np.random.randint(0,2,(3,3))
>>> b = np.random.randint(11,99,(2,3,3))
>>> a  # Index array
array([[1, 1, 0],
       [1, 0, 0],
       [0, 1, 1]])
>>> b  # values array
array([[[60, 34, 37],
        [41, 54, 41],
        [37, 69, 80]],

       [[91, 84, 58],
        [61, 87, 48],
        [45, 49, 78]]])
>>> m,n = a.shape
>>> I,J = np.ogrid[:m,:n]
>>> out = b[a, I, J]
>>> out
array([[91, 84, 37],
       [61, 54, 41],
       [37, 49, 78]])
like image 126
Divakar Avatar answered Nov 03 '22 16:11

Divakar


If your matrices get much bigger than 3x3, to the point that memory involved in np.ogrid is an issue, and if your indexes remain binary, you could also do:

np.where(a, b[1], b[0])

But other than that corner case (or if you like code golfing one-liners) the other answer is probably better.

like image 35
Daniel F Avatar answered Nov 03 '22 17:11

Daniel F


There is a numpy function off-the-shelf: np.choose. It also comes with some handy broadcast options.

import numpy as np    
cube = np.arange(18).reshape((2,3,3))
sel = np.array([[1, 0, 1], [0, 1, 1], [0,1,0]])

the_selection = np.choose(sel, cube)


>>>the_selection
array([[ 9,  1, 11],
       [ 3, 13, 14],
       [ 6, 16,  8]])

This method works with any 3D array.

like image 2
user2821 Avatar answered Nov 03 '22 17:11

user2821