Ответ 1
Я не могу придумать, как работать с этим в N измерениях, но вот 2D-версия:
>>> a = np.random.standard_normal(size=(2,5))
>>> a
array([[ 0.72322499, -0.05376714, -0.28316358, 1.43025844, -0.90814293],
[ 0.7459107 , 0.43020728, 0.05411805, -0.32813465, 2.38829386]])
>>> i = np.array([[0,1,2,4,3],[0,1,2,3,4]])
>>> a[np.arange(a.shape[0])[:,np.newaxis],i]
array([[ 0.72322499, -0.05376714, -0.28316358, -0.90814293, 1.43025844],
[ 0.7459107 , 0.43020728, 0.05411805, -0.32813465, 2.38829386]])
Вот N-мерная версия:
>>> a[list(np.ogrid[[slice(x) for x in a.shape]][:-1])+[i]]
Вот как это работает:
Хорошо, начнем с 3-мерного массива для иллюстрации.
>>> import numpy as np
>>> a = np.arange(24).reshape((2,3,4))
>>> a
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
Вы можете получить доступ к элементам этого массива, указав индекс вдоль каждой оси следующим образом:
>>> a[0,1,2]
6
Это эквивалентно a[0][1][2]
, так как вы будете обращаться к одному и тому же элементу, если бы мы имели дело со списком вместо массива.
Numpy позволяет вам стать еще более привлекательным при разрезании массивов:
>>> a[[0,1],[1,1],[2,2]]
array([ 6, 18])
>>> a[[0,1],[1,2],[2,2]]
array([ 6, 22])
Эти примеры были бы эквивалентны [a[0][1][2],a[1][1][2]]
и [a[0][1][2],a[1][2][2]]
, если бы мы имели дело со списками.
Вы можете даже оставить повторяющиеся индексы, и numpy будет определять, что вы хотите. Например, приведенные выше примеры могут быть эквивалентно записаны:
>>> a[[0,1],1,2]
array([ 6, 18])
>>> a[[0,1],[1,2],2]
array([ 6, 22])
Форма массива (или списка), который вы срезаете в каждом измерении, влияет только на форму возвращаемого массива. Другими словами, numpy не заботится о том, чтобы вы пытались индексировать массив массивом формы (2,3,4)
, когда он вытягивает значения, за исключением того, что он вернет вам массив формы (2,3,4)
. Например:
>>> a[[[0,0],[0,0]],[[0,0],[0,0]],[[0,0],[0,0]]]
array([[0, 0],
[0, 0]])
В этом случае мы снова и снова захватываем один и тот же элемент a[0,0,0]
, но numpy возвращает массив с той же формой, что и мы.
Хорошо, на вашу проблему. Вы хотите индексировать массив вдоль последней оси с числами в вашем массиве index
. Итак, для примера в вашем вопросе вы хотели бы [[a[0,0],a[0,1],a[0,2],a[0,4],a[0,3]],a[1,0],a[1,1],...
Тот факт, что ваш индексный массив является многомерным, как я уже говорил ранее, не говорит о том, что вы хотите вывести эти индексы с нуля. он просто определяет форму выходного массива. Итак, в вашем примере вам нужно указать numpy, что первые 5 значений нужно вытащить из a[0]
, а последние 5 из a[1]
. Легко!
>>> a[[[0]*5,[1]*5],index]
Он усложняется в N измерениях, но пусть это сделает для 3-мерного массива a
, который я определил выше. Предположим, что мы имеем следующий индексный массив:
>>> i = np.array(range(4)[::-1]*6).reshape(a.shape)
>>> i
array([[[3, 2, 1, 0],
[3, 2, 1, 0],
[3, 2, 1, 0]],
[[3, 2, 1, 0],
[3, 2, 1, 0],
[3, 2, 1, 0]]])
Итак, эти значения - все для индексов вдоль последней оси. Нам нужно указать numpy, какие индексы вдоль первой и второй осей должны быть взяты из этих чисел; то есть нам нужно указать numpy, что индексы для первой оси:
i1 = [[[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]],
[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]]]
и индексы для второй оси:
i2 = [[[0, 0, 0, 0],
[1, 1, 1, 1],
[2, 2, 2, 2]],
[[0, 0, 0, 0],
[1, 1, 1, 1],
[2, 2, 2, 2]]]
Тогда мы можем просто сделать:
>>> a[i1,i2,i]
array([[[ 3, 2, 1, 0],
[ 7, 6, 5, 4],
[11, 10, 9, 8]],
[[15, 14, 13, 12],
[19, 18, 17, 16],
[23, 22, 21, 20]]])
Удобная функция numpy, которая генерирует i1
и i2
, называется np.mgrid
. Я использую np.ogrid
в своем ответе, который эквивалентен в этом случае из-за магии numpy, о которой я говорил ранее.
Надеюсь, что это поможет!