Недостаток указателя в массивах 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 [индексы, которые вы хотите, строки, которые вы хотите, хотите ли вы)