Одной из сильных сторон Python является его единообразное применение простых принципов.Индекс Numpy, как и все индексы в Python, передает один аргумент методу индексированного объекта ( т.е. , массива) __getitem__
, и массивы Numpy были одним из основных обоснований для механизма среза (или прихотя бы одно из его самых ранних применений).
Когда я пытаюсь понять новое поведение, мне нравится начинать с конкретного и понятного примера, поэтому вместо 10x100 случайных значений я начну с одномерного4-элементный вектор и работа до 3х4, что должно быть достаточно большим, чтобы понять, что происходит.
simple = np.array([1, 2, 3, 4])
train = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]])
Интерпретатор показывает их как
array([1, 2, 3, 4])
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
Выражение simple[x]
эквивалентно (то есть интерпретатор завершает выполнение) simple.__getitem__(x)
изнутри - обратите внимание, что этот вызов принимает один аргумент.
Метод __getitem__
в массиве numpy-массива выполняет индексацию с целым числом очень просто:выбирает один элемент из первого измерения.Так что simple[1]
- это 2
, а train[1]
- это array([5, 6, 7, 8])
.
Когда __getitem__
получает кортеж в качестве аргумента (то есть, как синтаксис Python интерпретирует выражения, подобные array[x, y, z]
), он применяет каждыйэлемент кортежа в качестве индекса последовательных измерений индексируемого объекта.Таким образом, result = train[1, 2]
эквивалентно (концептуально - код более сложен в реализации) для
temp = train[1] # i.e. train.__getitem__(1)
result = temp[2] # i.e. temp.__getitem__(2)
и, конечно же, мы находим, что result
выходит на 7
.Вы могли бы думать о array[x, y, z]
как эквивалентном array[x][y][z]
.
Теперь мы можем добавить нарезку к миксу.Выражения, содержащие двоеточие, можно рассматривать как литералы среза (я не нашел для них лучшего названия), и интерпретатор создает для них slice объектов .Как отмечается в документации, объект слайса - это в основном контейнер для трех значений: start , stop и slice , и это зависит от метода __getitem__
каждого объектакак это их интерпретирует. этот вопрос может оказаться полезным для дальнейшего понимания нарезки.
Имея то, что вы теперь знаете, вы сможете понять ответ на свой первый вопрос.
result = train[:-1, 1:-1]
вызовет train.__getitem__
с двухэлементным набором срезов.Это эквивалентно
temp = train[:-1]
result = temp[..., 1:-1]
Первый оператор можно прочитать как «установить temp
для всех, кроме последней строки train
», а второй как «установить result
для всех, кромепервый и последний столбцы temp
".train[:-1]
равняется
array([[1, 2, 3, 4],
[5, 6, 7, 8]])
, и применение подписки [1:-1]
ко второму измерению этого массива дает
array([[2, 3],
[6, 7]])
. В первом измерении нижнего индекса temp
указано многоточие"пройти все", поэтому the subscript expression
[...] can be considered equivalent to
[:] . As far as the
Нет values are concerned, a slice has a maximum of three data points: _start_, _stop_ and _step_. A
Нет value for any of these gives the default value, which is
0 for _start_, the length of the indexed object for _stop_, and
1 for _step. So
x [Нет: Нет: Нет] is equivalent to
x [0: len (x): 1] which is equivalent to
x [::] `.
С этим знанием у вас есть немного больше шансов понять, что происходит.