Lets assume, I have two given ndarrays, where the matrix mapping contains information, of how row of the matrix mask should be permuted. We may assume, that the mapping matrix comes from some other algorithm.
import numpy as np
T, K, F = 2, 3, 5
mask = np.random.randint(4, size=(T, K, F))
mapping = np.asarray([
[0, 1, 2],
[0, 1, 2],
[2, 0, 1],
[0, 1, 2],
[1, 0, 2]
])
The straight forward way to do this, is by applying a for loop:
out = np.empty_like(mask)
for f in range(F):
out[:, :, f] = mask[:, mapping[f, :], f]
This seems to be quite efficient, so I looked at Numpy advanced indexing and found this solution:
out = mask[
np.arange(T)[:, None, None],
mapping.T[None, :, :],
np.arange(F)[None, None, :]
]
An answer to a related question suggests the use of ogrid:
ogrid = np.ogrid[:T, :1, :F]
out = mask[
ogrid[0],
mapping.T[None, :, :],
ogrid[2]
]
It seems very uncomfortable to create all the intermediate arrays and broadcast them correctly. So what is the best way, to perform the desired reordering?
Timing information:
To provide meaningful timing information, I used some shapes, closer to my application. The random permutation is just for brevity of the example.
T, K, F = 1000, 3, 257
mask = np.random.randint(4, size=(T, K, F))
mapping = np.stack([list(np.random.permutation(np.arange(3))) for _ in range(F)])
Here are the results:
for loop: 100 loops, best of 3: 8.4 ms per loop
three times broadcasting: 100 loops, best of 3: 8.37 ms per loop
ogrid: 100 loops, best of 3: 8.33 ms per loop
swapaxis: 100 loops, best of 3: 2.43 ms per loop
transpose: 100 loops, best of 3: 2.08 ms per loop