1

I'm having real trouble with this. I have a three-dimensional numpy array, and I'd like to re-order it by a two-dimensional indexing array. In reality the arrays will be determined programatically and the three-dimensional array may be two or four-dimensioned, but to keep things simple, here's the desired outcome if both arrays were two-dimensional:

ph = np.array([[1,2,3], [3,2,1]])
ph_idx = np.array([[0,1,2], [2,1,0]])
for sub_dim_n, sub_dim_ph_idx in enumerate(ph_idx):
    ph[sub_dim_n] = ph[sub_dim_n][sub_dim_ph_idx]

This makes the ph array into:

array([[1, 2, 3],
       [1, 2, 3]])

Which is what I'd like. Could anyone please help if it's the same circumstance, but instead of ph, I have a three-dimensional array (psh), like:

psh = np.array(
    [[[1,2,3]], 
     [[3,2,1]]]
)

Hope that's clear and please ask if it's not. Thanks in advance!

4
  • What would be an example of ph_idx in your three-dimensional case? Commented Nov 4, 2019 at 9:17
  • @fuglede - it would be (apologies for the formatting here) np.array([[[1,2,3]],[[1,2,3]]]) Commented Nov 4, 2019 at 9:32
  • Formatting is as good as it gets. Not [3, 2, 1] this time? Could you also provide an example where ph has shape (2, 2, 3)? Commented Nov 4, 2019 at 9:33
  • So, I didn't put this into the question because I didn't want to overcomplicate things, but ph might have a dim1 of length greater than 1 (like the 2, 2, 3 shape you suggested). If so I'm trying to apply the 2-d array. In something like numpy pseudocode, this would be ph[ph_idx[:, None, :]] Commented Nov 4, 2019 at 9:36

2 Answers 2

2

If what you want is to end up with a ph.shape shaped array, you could simply np.squeeze ph_ixs so the shapes match, and use it to index ph:

print(ph)
[[[1 2 3]]
 [[3 2 1]]]

print(ph_idx)
[[0 1 2]
 [2 1 0]]

np.take_along_axis(np.squeeze(ph), ph_idx, axis=-1)

array([[1, 2, 3],
       [1, 2, 3]])
Sign up to request clarification or add additional context in comments.

6 Comments

ph is the 3-dimensional array in their example, not ph_idx. That said, some variation of np.take_along_axis is probably what they're after.
That's a new function to me! Not available on 1.10 at least.
Thanks - I agree - take_along_axis looks like the function to use here.
@Chrisper: If all of your examples follow what you've outlined, you won't even need np.squeeze either; plain np.take_along_axis does the job.
@yatu: If you use the ph_idx from the comments to OP, you can even drop np.squeeze on ph.
|
2

So, the clues are already in the helpful comments here, but for completeness, it's as simple as using np.take_along_axis and a broadcasted version of the 2d array:

psh = np.array(
    [[[1,2,3]], 
     [[3,2,1]]]
)
ph_idx = np.array(
    [[0,1,2], 
     [2,1,0]]
)
np.take_along_axis(psh, ph_idx[:, None, :], axis=2)

This has the advantage of also working if the 3d array has a dim1 of more than one element:

psh = np.array(
    [[[1,2,3],[4,5,6],[7,8,9]], 
     [[3,2,1],[6,5,4],[9,8,7]]]
)
ph_idx = np.array([[0,1,2], [2,1,0]])
np.take_along_axis(psh, ph_idx[:, None, :], axis=2)

which gives

array([[[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]],

       [[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]]])

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.