0

I have a numpy array A with shape (a, b, c), and another integer array L with shape (a, b). I want to make an array B such that B[i, j, k] = A[L[i, j],j, k] (assume shapes and values of L permit this).

What is the most efficient way to do this? The only ways I can think to do it involve creating meshgrids or new tiled arrays to expand L to the same shape as A which feels inefficient and not very nice. Surely this is quite a standard thing to do with an efficient implementation somewhere (is there an einops way?)?

I used einops einops.rearrange(A, i j k -> (i j) k) and flattened L similarly, indexed the first coordinate by L and reshaped back. This seems kind of stupid -- I am doing it like this because I don't really understand numpy indexing.

4
  • You need L of size (a,b,2) then B[i, j, k] = A[L[i, j,0], L[i, j,1], k] Commented Jun 4, 2024 at 23:09
  • If L is of shape (a,b) then call to L[a,b] will return single value float/int` and so you can't broadcast one value to two dimensions. Commented Jun 4, 2024 at 23:11
  • A: (a,b,c) -> float then L: (i,j) -> (a,b) this means that L[i,j] stores two values and it is actually and L[i,j,2] Commented Jun 4, 2024 at 23:13
  • 2
    Give a minimal reproducible example, and some code that does the job, even it isn't the most efficient. That will ensure that your specification is complete. Commented Jun 5, 2024 at 0:43

1 Answer 1

1
a, b, c = 5, 7, 4
A = np.random.rand(a, b, c)

# L indexes the first axis of A,
# so pick random indices that are lower than `a`:
L = np.random.randint(a, size=(a, b))

# Solution: create some indexers for the other axes:
j, k = np.indices((b, c), sparse=True)
# The broadcasting works in this case, because `L` indexes the first axis.
# In other situations, the following might be more robust:
# _, j, k = np.indices((a, b, c), sparse=True)

# Finally do the indexing:
B = A[L[:, :, None], j, k]

Checking:

B2 = np.zeros_like(A)
for i in range(a):
    for j in range(b):
        for k in range(c):
            B2[i, j, k] = A[L[i, j], j, k]

assert np.array_equal(B, B2)
Sign up to request clarification or add additional context in comments.

2 Comments

You can also expand the indices: B = A[L[:, :, None], *np.indices((b, c), sparse=True)] :)
Or A[L[:, :, None], *np.indices((a, b, c), sparse=True)[1:]] for the variant

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.