NumPy: массивы, форма и индексация

Базовая индексация: элементы, строки, столбцы и срезы

Содержание курса

Срез start:stop:step и прямоугольный блок по двум осям

Если целый индекс выбирает одну конкретную позицию, то срез выбирает диапазон позиций вдоль оси. Полная форма записи — start:stop:step, где:

  • start — с какой позиции начинать (включительно);
  • stop — до какой позиции идти (не включая её);
  • step — шаг между выбираемыми позициями.

Любой из трёх параметров можно опустить. При положительном шаге: пропущенный start означает начало оси, пропущенный stop — конец оси, пропущенный step — шаг 1. При отрицательном шаге пропущенные границы меняются на противоположные: движение начинается с последнего элемента и идёт к позиции перед первым.

Посмотрим на одномерном примере:

import numpy as np

v = np.array([10, 20, 30, 40, 50, 60])

print(v[1:4])    # [20, 30, 40]  — позиции 1, 2, 3
print(v[::2])    # [10, 30, 50]  — каждый второй с начала
print(v[1::2])   # [20, 40, 60]  — каждый второй, начиная с позиции 1
print(v[::-1])   # [60, 50, 40, 30, 20, 10]  — обратный порядок

v[1:4] берёт позиции 1, 2, 3 — три элемента. v[::2] идёт от начала до конца с шагом 2. v[::-1] — отрицательный шаг: пропущенные start и stop по умолчанию задают движение от последнего элемента к первому включительно, что даёт разворот массива.

Переход в два измерения. Для двумерного массива срезы по строкам и по столбцам записываются через запятую: arr[r1:r2, c1:c2]. Это выбирает прямоугольный блок: строки от r1 до r2-1 и столбцы от c1 до c2-1.

arr = np.arange(12).reshape(3, 4)
# [[ 0,  1,  2,  3],
#  [ 4,  5,  6,  7],
#  [ 8,  9, 10, 11]]

print(arr[0:2, 1:3])
# [[1, 2],
#  [5, 6]]

arr[0:2, 1:3] — строки 0 и 1, столбцы 1 и 2. Получаем прямоугольный блок 2×2.

Можно применять шаг сразу по обеим осям:

print(arr[::2, ::2])
# [[ 0,  2],
#  [ 8, 10]]

По строкам шаг 2 — берём строки 0 и

  1. По столбцам шаг 2 — берём столбцы 0 и
  2. Результат снова прямоугольный.

Комбинация среза с целым индексом. Ничто не мешает задать по одной оси срез, а по другой — конкретный индекс:

print(arr[1:3, 0])
# [4, 8]

Здесь по строкам — срез 1:3 (строки 1 и 2), по столбцам — целый индекс 0. Ось столбцов схлопывается, остаётся одномерный массив из двух элементов. Это принципиально отличает такой вызов от arr[1:3, 0:1]: последний сохранит ось столбцов и вернёт shape (2, 1), а не (2,). Правило простое: срез сохраняет ось, целый индекс убирает её — но о том, как из этого вычислять shape результата, поговорим в следующем разделе.

Базовая индексация: элементы, строки, столбцы и срезы — NumPy и pandas: практический тренажёр — Latorn