Введение в индексацию в NumPy

NumPyBeginner
Практиковаться сейчас

Введение

С возвращением! Теперь, когда вы понимаете, как создавать массивы NumPy, пришло время научиться получать доступ к данным внутри них и манипулировать ими. В этой лабораторной работе вы изучите индексацию — основной метод доступа и изменения данных в массивах NumPy.

Опираясь на изученное

В предыдущей лабораторной работе вы узнали:

  • Как создавать массивы с помощью различных функций NumPy
  • Разницу между массивами и списками Python
  • Размеры массивов (1D, 2D, 3D) и типы данных

Теперь вы научитесь:

  • Получать доступ к отдельным элементам или группам элементов
  • Извлекать определенные строки, столбцы или области из массивов
  • Использовать продвинутые методы выбора для сложной фильтрации данных
  • Изменять данные массива с помощью индексации

Почему индексация важна

Индексация является фундаментальной для манипуляции данными, поскольку она позволяет вам:

  • Извлекать подмножества данных для анализа
  • Изменять конкретные значения в больших наборах данных
  • Фильтровать данные на основе условий
  • Выполнять векторизованные операции над выбранными элементами

Эти навыки необходимы для любой задачи анализа данных или научных вычислений в Python.

Базовая индексация и срезы в одномерных массивах

Теперь, когда вы знаете, как создавать массивы, давайте научимся получать доступ к их содержимому. Вся ваша работа в этой лабораторной будет проводиться в файле indexing_practice.py.

Понимание индексации массивов

Нулевая индексация

Как и списки Python, массивы NumPy используют нулевую индексацию. Это означает:

  • Первый элемент находится по индексу 0
  • Второй элемент находится по индексу 1
  • И так далее...

Визуализация индексов массива

Для массива x = [10, 20, 30, 40, 50]:

Индекс:  0   1   2   3   4
Значение: 10  20  30  40  50

Таким образом, x[0] дает 10, x[2] дает 30 и т.д.

Синтаксис срезов

Срезы позволяют выбирать диапазон элементов с использованием синтаксиса start:stop:step:

  • start: Индекс, с которого начинается срез (включительно)
  • stop: Индекс, на котором заканчивается срез (исключительно)
  • step: Сколько элементов пропускать (необязательно, по умолчанию 1)

Распространенные шаблоны срезов:

  • x[1:4]: Элементы по индексам 1, 2, 3
  • x[:3]: Первые 3 элемента (индексы 0, 1, 2)
  • x[2:]: От индекса 2 до конца
  • x[::2]: Каждый второй элемент, начиная с индекса 0
  • x[::-1]: Обратить весь массив

Сначала откройте файл indexing_practice.py в редакторе. Затем замените все его содержимое следующим кодом. Этот код создает одномерный массив и демонстрирует, как получить доступ к отдельному элементу и срезу элементов.

import numpy as np

## Создаем одномерный массив с числами от 0 до 9
x = np.arange(10)
print("Original array:", x)

## Получаем доступ к отдельному элементу по индексу 2
element = x[2]
print("Element at index 2:", element)

## Делаем срез массива от индекса 1 до индекса 7 (не включая его) с шагом 2
a_slice = x[1:7:2]
print("Slice from 1 to 7 with step 2:", a_slice)

После добавления кода в indexing_practice.py сохраните файл. Теперь запустите скрипт из терминала, выполнив следующую команду:

python indexing_practice.py

Вы должны увидеть следующий вывод, который показывает исходный массив, элемент по указанному индексу и полученный срез.

Original array: [0 1 2 3 4 5 6 7 8 9]
Element at index 2: 2
Slice from 1 to 7 with step 2: [1 3 5]

Индексация многомерных массивов

Теперь давайте поработаем с массивами, имеющими более одного измерения. Именно здесь NumPy действительно превосходит списки Python!

Мышление в многомерных пространствах

Двумерные массивы как таблицы

Двумерный массив похож на электронную таблицу или таблицу:

  • Строки — это первое измерение (горизонтальное)
  • Столбцы — это второе измерение (вертикальное)
  • Вы указываете индексы как строки, так и столбца: array[row, column]

Визуализация двумерной индексации

Для двумерного массива:

array = [[10, 20, 30],
         [40, 50, 60],
         [70, 80, 90]]

Индексы:     0,0  0,1  0,2
             1,0  1,1  1,2
             2,0  2,1  2,2
  • array[0, 0] → 10 (первая строка, первый столбец)
  • array[1, 2] → 60 (вторая строка, третий столбец)
  • array[2, 1] → 80 (третья строка, второй столбец)

Выбор целых строк или столбцов

  • array[0] или array[0, :] → вся первая строка [10, 20, 30]
  • array[:, 1] → весь второй столбец [20, 50, 80]
  • Это гораздо удобнее, чем вложенные списки Python!

Давайте попрактикуемся с двумерным (2D) массивом. Обновите ваш файл indexing_practice.py кодом ниже. Этот скрипт создает массив 3x4 и показывает, как получить доступ к отдельному элементу и целой строке.

import numpy as np

## Создаем двумерный массив (3 строки, 4 столбца)
x = np.arange(12).reshape(3, 4)
print("Original 2D array:\n", x)

## Получаем доступ к элементу в строке 1, столбце 2
element = x[1, 2]
print("\nElement at (1, 2):", element)

## Получаем доступ ко всей первой строке (индекс строки 0)
first_row = x[0]
print("\nFirst row:", first_row)

Сохраните файл и снова запустите его из терминала:

python indexing_practice.py

Вывод отобразит двумерный массив и выбранные вами части.

Original 2D array:
 [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

Element at (1, 2): 6

First row: [0 1 2 3]

Расширенная индексация

Базовые срезы хорошо работают для непрерывных областей, но иногда вам нужны более сложные выборки. NumPy предоставляет две мощные техники расширенной индексации:

Индексация массивом целых чисел

Выбирайте произвольные элементы, предоставляя массив индексов. Это похоже на выбор конкретных элементов из списка по их позициям.

Пример из реальной жизни: У вас есть оценки за тесты, и вы хотите проверить оценки студентов на позициях 3, 7 и 12:

scores = np.array([85, 92, 78, 95, 88, 76, 91, 89, 84, 93, 87, 90, 82])
student_positions = [3, 7, 12]  ## Студенты, которые вас интересуют
selected_scores = scores[student_positions]  ## [95, 89, 82]

Индексация булевым массивом (маскирование)

Выбирайте элементы на основе условий. Создайте "маску" из значений True/False, затем используйте ее для фильтрации массива.

Пример из реальной жизни: Отфильтруйте проходные оценки (≥ 80) из класса:

scores = np.array([85, 92, 78, 95, 88, 76, 91, 89, 84, 93])
passing_mask = scores >= 80  ## [True, True, False, True, True, False, True, True, True, True]
passing_scores = scores[passing_mask]  ## [85, 92, 95, 88, 91, 89, 84, 93]

Почему это важно

  • Индексация целыми числами: Идеально подходит для выборки конкретных точек данных
  • Булева индексация: Идеально подходит для фильтрации данных и условного выбора
  • Оба метода создают копии (не представления), поэтому изменения не влияют на исходный массив

Давайте попробуем оба. Замените содержимое indexing_practice.py следующим кодом:

import numpy as np

## --- Индексация массивом целых чисел ---
x = np.arange(10, 0, -1)
print("Array for integer indexing:", x)

## Выбираем элементы по индексам 3, 3, 1 и 8
selected_elements = x[np.array([3, 3, 1, 8])]
print("Selected elements with integer array:", selected_elements)


## --- Индексация булевым массивом ---
y = np.array([1., -1., -2., 3.])
print("\nArray for boolean indexing:", y)

## Создаем булеву маску для отрицательных элементов
mask = y < 0
print("Boolean mask (y < 0):", mask)

## Выбираем элементы, где условие истинно (True)
negative_elements = y[mask]
print("Elements where y < 0:", negative_elements)

Сохраните файл и запустите скрипт:

python indexing_practice.py

Ваш вывод должен продемонстрировать, как работают как целочисленная, так и булева индексация для выбора конкретных данных из ваших массивов.

Array for integer indexing: [10  9  8  7  6  5  4  3  2  1]
Selected elements with integer array: [7 7 9 2]

Array for boolean indexing: [ 1. -1. -2.  3.]
Boolean mask (y < 0): [False  True  True False]
Elements where y < 0: [-1. -2.]

Присваивание значений индексированным массивам

Индексация используется не только для чтения данных, но и для изменения данных. Вы можете использовать любой метод индексации в левой части оператора присваивания (=) для изменения конкретных элементов.

Broadcasting: Согласование форм

При присваивании значений индексированным массивам NumPy использует broadcasting для согласования форм. Это одна из самых мощных функций NumPy!

Правила Broadcasting

NumPy может автоматически расширять меньшие массивы для соответствия большим во время присваивания, следуя этим правилам:

  1. Одно значение нескольким элементам: Одно значение может быть присвоено многим позициям
  2. Малый массив к большей выборке: Пока размеры совместимы

Примеры Broadcasting при присваивании

## Одно значение срезу
arr = np.array([1, 2, 3, 4, 5])
arr[1:4] = 99  ## [1, 99, 99, 99, 5]

## Массив к соответствующему срезу
arr = np.array([1, 2, 3, 4, 5])
arr[1:4] = [10, 20, 30]  ## [1, 10, 20, 30, 5]

## Булева индексация с broadcasting
arr = np.array([1, 2, 3, 4, 5])
arr[arr % 2 == 0] = -1  ## Заменяем все четные числа на -1

Важные замечания

  • Broadcasting работает только при совместимости форм
  • Форма присваиваемого значения должна "вписываться" в индексированную выборку
  • Это гораздо эффективнее, чем ручное перебирание элементов в цикле

Обновите ваш файл indexing_practice.py следующим кодом, чтобы увидеть это в действии.

import numpy as np

## --- Присваивание одного значения срезу ---
x = np.arange(10)
print("Original array:", x)

## Присваиваем значение 99 элементам от индекса 2 до 4
x[2:5] = 99
print("After assigning 99 to slice [2:5]:", x)


## --- Присваивание значений на основе булевого условия ---
y = np.arange(10)
print("\nOriginal array:", y)

## Присваиваем значение -1 всем четным числам
y[y % 2 == 0] = -1
print("After assigning -1 to even numbers:", y)

Сохраните файл и запустите его из терминала:

python indexing_practice.py

Вывод покажет массивы до и после модификации, демонстрируя, насколько мощной является эта функция для манипулирования данными.

Original array: [0 1 2 3 4 5 6 7 8 9]
After assigning 99 to slice [2:5]: [ 0  1 99 99 99  5  6  7  8  9]

Original array: [0 1 2 3 4 5 6 7 8 9]
After assigning -1 to even numbers: [-1  1 -1  3 -1  5 -1  7 -1  9]

Резюме

В этой лабораторной работе вы изучили основные методы индексации массивов NumPy. Вы начали с базового доступа к отдельным элементам и срезов в одномерных массивах, аналогично спискам Python. Затем вы перешли к индексации многомерных массивов для выбора конкретных элементов и подмассивов. Наконец, вы изучили расширенную индексацию с использованием массивов целых чисел и булевых массивов, а также узнали, как использовать эти мощные методы выбора для изменения данных внутри массива. Эти навыки являются основополагающими для эффективной манипуляции данными и их анализа в Python с использованием NumPy.