Вот как NumPy использует расширенную индексацию для трансляции форм массива. Когда вы передаете a 0
для первого индекса и y
для последнего индекса, numpy будет транслировать, 0
чтобы иметь ту же форму, что и y
. Эквивалентность имеет место x[0,:,:,y] == x[(0, 0, 0),:,:,y]
. вот пример
import numpy as np
x = np.arange(120).reshape(2,3,4,5)
y = np.array([0,2,4])
np.equal(x[0,:,:,y], x[(0, 0, 0),:,:,y]).all()
# returns:
True
Теперь, поскольку вы фактически передаете два набора индексов, вы используете API расширенного индексирования для формирования (в данном случае) пар индексов.
x[(0, 0, 0),:,:,y])
# equivalent to
[
x[0,:,:,y[0]],
x[0,:,:,y[1]],
x[0,:,:,y[2]]
]
# equivalent to
rows = np.array([0, 0, 0])
cols = y
x[rows,:,:,cols]
# equivalent to
[
x[r,:,:,c] for r, c in zip(rows, columns)
]
Который имеет первое измерение, которое равно длине y
. Это то, что вы видите.
В качестве примера рассмотрим массив с 4 измерениями, которые описаны в следующем фрагменте:
x = np.arange(120).reshape(2,3,4,5)
y = np.array([0,2,4])
# x looks like:
array([[[[ 0, 1, 2, 3, 4], -+ =+
[ 5, 6, 7, 8, 9], Sheet1 |
[ 10, 11, 12, 13, 14], | |
[ 15, 16, 17, 18, 19]], -+ |
Workbook1
[[ 20, 21, 22, 23, 24], -+ |
[ 25, 26, 27, 28, 29], Sheet2 |
[ 30, 31, 32, 33, 34], | |
[ 35, 36, 37, 38, 39]], -+ |
|
[[ 40, 41, 42, 43, 44], -+ |
[ 45, 46, 47, 48, 49], Sheet3 |
[ 50, 51, 52, 53, 54], | |
[ 55, 56, 57, 58, 59]]], -+ =+
[[[ 60, 61, 62, 63, 64],
[ 65, 66, 67, 68, 69],
[ 70, 71, 72, 73, 74],
[ 75, 76, 77, 78, 79]],
[[ 80, 81, 82, 83, 84],
[ 85, 86, 87, 88, 89],
[ 90, 91, 92, 93, 94],
[ 95, 96, 97, 98, 99]],
[[100, 101, 102, 103, 104],
[105, 106, 107, 108, 109],
[110, 111, 112, 113, 114],
[115, 116, 117, 118, 119]]]])
x
имеет действительно легко понять последовательную форму, которую мы можем теперь использовать, чтобы показать, что происходит ...
Первое измерение похоже на наличие двух книг Excel, второе измерение похоже на наличие трех листов в каждой книге, третье измерение похоже на наличие 4 строк на листе, а последнее измерение составляет 5 значений для каждой строки (или столбцов на листе).
Глядя на это так, спрашивая x[0,:,:,0]
, можно сказать: «в первой книге, для каждого листа, для каждой строки, дайте мне первое значение / столбец».
x[0,:,:,y[0]]
# returns:
array([[ 0, 5, 10, 15],
[20, 25, 30, 35],
[40, 45, 50, 55]])
# this is in the same as the first element in:
x[(0,0,0),:,:,y]
Но теперь с расширенным индексированием мы можем думать x[(0,0,0),:,:,y]
как «в первой книге, для каждого листа, для каждой строки, дайте мне y
значение th / столбец. Хорошо, теперь сделайте это для каждого значения y
»
x[(0,0,0),:,:,y]
# returns:
array([[[ 0, 5, 10, 15],
[20, 25, 30, 35],
[40, 45, 50, 55]],
[[ 2, 7, 12, 17],
[22, 27, 32, 37],
[42, 47, 52, 57]],
[[ 4, 9, 14, 19],
[24, 29, 34, 39],
[44, 49, 54, 59]]])
Где он сходит с ума, так это то, что numpy будет транслироваться, чтобы соответствовать внешним измерениям массива индекса. Поэтому, если вы хотите выполнить ту же операцию, что и выше, но для ОБА «книг Excel», вам не нужно зацикливаться и объединять. Вы можете просто передать массив в первое измерение, но он ДОЛЖЕН иметь совместимую форму.
Передача целого числа транслируется на y.shape == (3,)
. Если вы хотите передать массив в качестве первого индекса, только последнее измерение массива должно быть совместимо с y.shape
. Т.е. последнее измерение первого индекса должно быть 3 или 1.
ix = np.array([[0], [1]])
x[ix,:,:,y].shape
# each row of ix is broadcast to length 3:
(2, 3, 3, 4)
ix = np.array([[0,0,0], [1,1,1]])
x[ix,:,:,y].shape
# this is identical to above:
(2, 3, 3, 4)
ix = np.array([[0], [1], [0], [1], [0]])
x[ix,:,:,y].shape
# ix is broadcast so each row of ix has 3 columns, the length of y
(5, 3, 3, 4)
В документах нашел краткое объяснение: https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#combining-advanced-and-basic-indexing.
Редактировать:
Исходя из первоначального вопроса, чтобы получить одну строку нужного сублицензирования, вы можете использовать x[0][:,:,y]
:
x[0][:,:,y].shape
# returns
(2, 50, 3)
Однако, если вы пытаетесь назначить этим сублимам, вы должны быть очень осторожны, когда смотрите на общий вид памяти исходного массива. В противном случае присваивание будет не исходному массиву, а копии.
Общая память возникает только тогда, когда вы используете целое число или фрагмент для подмножества вашего массива, то есть x[:,0:3,:,:]
или x[0,:,:,1:-1]
.
np.shares_memory(x, x[0])
# returns:
True
np.shares_memory(x, x[:,:,:,y])
# returns:
False
И в вашем оригинальном вопросе, и в моем примере y
нет ни int, ни slice, поэтому всегда будет назначаться копия оригинала.
НО! Поскольку ваш массив для y
может быть выражен в виде среза, вы МОЖЕТЕ получить назначаемое представление вашего массива через:
x[0,:,:,0:21:10].shape
# returns:
(2, 50, 3)
np.shares_memory(x, x[0,:,:,0:21:10])
# returns:
True
# actually assigns to the original array
x[0,:,:,0:21:10] = 100
Здесь мы используем фрагмент, 0:21:10
чтобы получить каждый индекс, который будет в range(0,21,10)
. Мы должны использовать, 21
а не 20
потому, что точка останова исключена из среза, как в range
функции.
Таким образом, в принципе, если вы можете создать срез, который соответствует вашим критериям сублицензирования, вы можете сделать назначение.