Решение с использованием расширенного индексирования Integer:
Дано:
source = [[0.0, 0.1, 0.2, 0.3],
[1.0, 1.1, 1.2, 1.3],
[2.0, 2.1, 2.2, 2.3]]
indices = [[[3, 1, 0, 1],
[3, 0, 0, 3]],
[[0, 1, 0, 2],
[3, 2, 1, 1]],
[[1, 1, 0, 1],
[0, 1, 2, 2]]]
Используйте это:
import numpy as np
nd_source = np.array(source)
source_rows = len(source) # == 3, in above example
source_cols = len(source[0]) # == 4, in above example
row_indices = np.arange(source_rows).reshape(-1,1,1)
result = nd_source [row_indices, indices]
Результат:
print (result)
[[[0.3 0.1 0. 0.1]
[0.3 0. 0. 0.3]]
[[1. 1.1 1. 1.2]
[1.3 1.2 1.1 1.1]]
[[2.1 2.1 2. 2.1]
[2. 2.1 2.2 2.2]]]
Пояснение:
Для использования Integer Advanced Indexing применяются следующие ключевые правила:
- Мы должны предоставить индексные массивы, состоящие из целочисленных индексов.
- Мы должны предоставить столько индексных массивов, сколько имеется измерений в исходном массиве.
- Форма этих индексных массивов должна быть одинаковой или, по крайней мере, все они должны быть транслируемыми в одну конечную форму.
Как работает Integer Advanced Indexing:
Учитывая, что исходный массив имеет n
измерения, и поэтому мы предоставили n
массивы целочисленных индексов:
- Все эти индексные массивы, если они не будут иметь одинаковую однородную форму, будут транслироваться в единой однородной форме.
- Чтобы получить доступ к любому элементу в исходном массиве, нам, очевидно, нужен набор из n индексов. Поэтому, чтобы сгенерировать массив результатов из исходного массива, нам нужно несколько n-кортежей, по одному n-кортежу для каждой позиции элемента массива конечных результатов. Для каждой позиции элемента результирующего массива n-кортеж индексов будет построен из соответствующих позиций элементов в широковещательных индексных массивах. (Помните, что результирующий массив имеет точно такую же форму, что и переданные индексные массивы, как уже упоминалось выше).
- Таким образом, путем обхода индексных массивов в тандеме , мы получаем все n-кортежи, которые нам нужны для генерации результирующего массива, в той же форме, что и широковещательные индексные массивы.
Применение этого объяснения к приведенному выше примеру:
- Наш исходный массив -
nd_source = np.array(source)
, то есть 2d.
Наша конечная форма результата (3,2,4)
.
Поэтому нам необходимо предоставить индексные массивы 2
, и эти индексные массивы должны либо иметь конечную форму результата (3,2,4)
, либо передаваться в формате (3,2,4)
.
Наш первый индексный массив - row_indices = np.arange(source_rows).reshape(-1,1,1)
. (source_rows
- это число строк в источнике, которое в данном примере равно 3
). Этот индексный массив имеет форму (3,1,1)
и фактически выглядит как [[[0]],[[1]],[[2]]]
. Это может быть передано в конечную форму результата (3,2,4)
, а транслируемый массив выглядит как [[[0,0,0,0],[0,0,0,0]],[[1,1,1,1],[1,1,1,1]],[[2,2,2,2],[2,2,2,2]]]
.
Наш второй индексный массив - indices
. Хотя это не массив, а всего лишь список списков, numpy достаточно гибок, чтобы автоматически преобразовывать его в соответствующий ndarray, когда мы передаем его в качестве массива индекса отправки. Обратите внимание, что этот массив уже имеет конечную желаемую форму результата (3,2,4)
даже без какой-либо широковещательной передачи.
Обход этих двух индексных массивов в тандеме (один широковещательный массив, а другой как есть), numpy генерирует все 2 кортежа, необходимые для доступа к нашему исходному 2d массиву nd_source
, и сформировать окончательный результат в форме (3,2,4)
.