</>
Тема 3 из 6

Индексы и срезы

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

Одномерный массив

Индексы и срезы работают как у списков:

import numpy as np

a = np.array([5, 8, 2, 9, 4, 7])
print(a[0], a[-1])    # 5 7
print(a[1:4])         # [8 2 9]
print(a[::2])         # [5 2 4] — каждый второй
print(a[::-1])        # [7 4 9 2 8 5] — наоборот

Таблица: индекс через запятую

В двумерном массиве индексы по осям пишутся через запятую в одних скобках:

m = np.array([[1, 2, 3, 4],
              [5, 6, 7, 8],
              [9, 10, 11, 12]])
print(m[2, 1])        # 10 — строка 2, столбец 1
print(m[0])           # [1 2 3 4] — вся строка 0
print(m[:, 3])        # [ 4  8 12] — весь столбец 3

Двоеточие : означает «всё по этой оси». Запись m[2][1] тоже работает, но m[2, 1] — правильный стиль numpy и быстрее.

Срез таблицы — прямоугольник

Срезы по обеим осям вырезают прямоугольный кусок:

print(m[0:2, 1:3])
# [[2 3]
#  [6 7]]
print(m[1:, ::2])     # строки с 1-й, столбцы через один
# [[ 5  7]
#  [ 9 11]]

Как и в Python, правая граница среза не входит. Если в задаче строки нумеруются с единицы и обе границы включены, отрезок с r1 по r2 — это срез r1 - 1 : r2.

Срез — это окно, а не копия

Важное отличие от списков: срез массива не копирует данные, а смотрит в тот же участок памяти:

a = np.arange(5)          # [0 1 2 3 4]
part = a[1:4]
part[:] = 0               # обнулили «кусок»
print(a)                  # [0 0 0 0 4] — исходный массив тоже изменился

Это экономит память на больших данных. Если нужна независимая копия — a[1:4].copy().

Срезом можно и присваивать:

m[:, 0] = 0               # обнулить первый столбец
m[1] = [7, 7, 7, 7]       # заменить строку

Выбор по списку индексов

Если в скобки передать список или массив индексов, numpy соберёт элементы с этими позициями в указанном порядке:

colors = np.array(["red", "green", "blue", "black"])
print(colors[[2, 0, 2]])          # ['blue' 'red' 'blue']

idx = np.array([3, 1])
print(colors[idx])                # ['black' 'green']

Это называется fancy indexing. В отличие от среза, результат — новый массив (копия). Индексы могут повторяться и идти в любом порядке — поэтому так удобно переставлять элементы.

Для таблиц можно выбирать строки списком: m[[2, 0]] — строки 2 и 0, или конкретные клетки парами списков: m[[0, 2], [1, 3]] — элементы (0,1) и (2,3).

Итог

  • m[i, j] — элемент, m[i] — строка, m[:, j] — столбец;
  • m[r1:r2, c1:c2] — прямоугольник, правые границы не входят;
  • срез — окно в те же данные; копия — .copy();
  • a[[i1, i2, ...]] — элементы по списку индексов, в заданном порядке.