Недостаток указателя в массивах numpy

Я действительно смущен логикой индекса массивов numpy с несколькими измерениями. Вот пример:

import numpy as np
A = np.arange(18).reshape(3,2,3)
[[[ 0,  1,  2],
  [ 3,  4,  5]],

 [[ 6,  7,  8],
  [ 9, 10, 11]],

 [[12, 13, 14],
  [15, 16, 17]]])

это дает мне массив формы (3,2,3), называет их (x, y, z) ради аргумента. Теперь я хочу массив B с элементами из A, соответствующими x = 0,2 y = 0,1 и z = 1,2. Как

array([[[ 1,  2],
        [4,  5]],

       [[13, 14],
        [16, 17]]])

Наивно я думал, что

B=A[[0,2],[0,1],[1,2]]

выполнит эту работу. Но он дает

array([  2, 104]) 

и не работает.

A[[0,2],:,:][:,:,[1,2]]

выполняет эту работу. Но я все еще удивляюсь, что случилось с моей первой попыткой. И какой лучший способ сделать то, что я хочу сделать?

Ответы

Ответ 1

Существует два типа индексирования в NumPy basic и advanced. Базовая индексация использует кортежи ломтиков для индексации и не копирует массив, а создает представление с откорректированным strides. Продвинутая индексация по контрасту также использует списки или массивы индексов и копирует массив.

Ваша первая попытка

B = A[[0, 2], [0, 1], [1, 2]]

использует расширенную индексацию. В расширенной индексации все индексные списки сначала передаются в одну и ту же форму, и эта форма используется для выходного массива. В этом случае они уже имеют одинаковую форму, поэтому трансляция ничего не делает. Выходной массив также будет иметь эту форму из двух записей. Первая запись выходного массива получается с использованием всех первых индексов трех списков, а вторая - с использованием всех вторых индексов:

B = numpy.array([A[0, 0, 1], A[2, 1, 2]])

Ваш второй подход

B = A[[0,2],:,:][:,:,[1,2]]

работает, но он неэффективен. Он дважды использует расширенную индексацию, поэтому ваши данные будут скопированы дважды.

Чтобы получить то, что вы действительно хотите с помощью расширенной индексации, вы можете использовать

A[np.ix_([0,2],[0,1],[1,2])]

как указано nikow. Это скопирует данные только один раз.

В вашем примере вы можете обойтись без копирования данных вообще, используя только базовое индексирование:

B = A[::2, :, 1:2]

Ответ 2

Я рекомендую следующее расширенное руководство, в котором объясняются различные методы индексирования: NumPy MedKit

Как только вы поймете мощные способы индексирования массивов (и как их можно объединить), это будет иметь смысл. Если ваша первая попытка была действительной, это столкнулось бы с некоторыми другими методами индексирования (уменьшая ваши варианты в других случаях использования).

В вашем примере вы можете использовать, что третий индекс охватывает непрерывный диапазон:

 A[[0,2],:,1:]

Вы также можете использовать

A[np.ix_([0,2],[0,1],[1,2])]

что удобно в более общих случаях, когда последние индексы не являются непрерывными. np.ix_ просто создает три массива индексов.

Как указал Свен в своем ответе, в этом конкретном случае есть более эффективный способ (используя представление вместо скопированной версии).

Изменить: Как указал Свен, мой ответ содержал некоторые ошибки, которые я удалил. Я все еще думаю, что его ответ лучше, но, к сожалению, я не могу удалить сейчас.

Ответ 3

A[(0,2),:,1:]

Если вы хотите

array([[[ 1,  2],
        [ 4,  5]],

       [[13, 14],
        [16, 17]]])

A [индексы, которые вы хотите, строки, которые вы хотите, хотите ли вы)