Чтобы проанализировать данные, можно провести множество разных операций:
- Сравнить значения
- Поискать минимальные и максимальные значения
- Найти суммы и произведения элементов
И это далеко не полный список всех доступных преобразований. В некоторых случаях вычисления над элементами требуют использования более сложных математических операций и функций. Именно под это заточена библиотека Numpy, которая позволяет не только готовить данные к обработке, но и проводить необходимые вычисления. В этом уроке мы разберемся, как эти вычисления работают и как применять их на практике.
Поэлементные преобразования и укладывание
Numpy помогает ускорить операции и упростить синтаксис — так происходит благодаря поэлементным преобразованиям. Он позволяет оперировать с данными разной размерности. Такой подход называется укладыванием.
Чтобы погрузиться в эту тему глубже, познакомимся с распространенными задачами с арифметическими операциями над данными и выясним, как работает укладывание элементов одного массива данных в другой.
Чтобы выполнять арифметические операции со стандартными структурами данных в Python, нужно использовать циклы. Их количество и вложенность зависит от размерности. Numpy работает по-другому — логика и синтаксические конструкции в операциях над массивами остается одинаковой для структур разной размерности. Для оптимизации и повышения качества кода циклы скрыты от пользователя.
Посмотрим на пример ниже. В нем показан ряд операций над одномерным массивом данных и числовым значением, которое поэлементно применяется ко всему массиву:
import numpy as np
# Исходный массив
arr1 = np.array([0, 1, 2, 3, 4, 5, 6, 7])
# Значение для изменения элементов массива
change_array_value = 5
print(arr1 + change_array_value)
# => [ 5 6 7 8 9 10 11 12]
print(arr1 - change_array_value)
# => [-5 -4 -3 -2 -1 0 1 2]
print(arr1 * change_array_value)
# => [ 0 5 10 15 20 25 30 35]
print(arr1 / change_array_value)
# => [0. 0.2 0.4 0.6 0.8 1. 1.2 1.4]
Циклы в примере выше отсутствуют. Как мы уже говорили, в Numpy это называется укладыванием. Укладывание элемента в массив было разобрано на примере вектора и числа. Однако укладывать можно не только один элемент, а любой массив подходящего размера — при условии, если структура большей размерности. Посмотрим на пример прибавления элементов вектора построчно к матрице:
# Добавление вектора к матрице
matrix_array = np.array([[5, 8], [8, 9]])
vector_array = np.array([1, 2])
print(matrix_array + vector_array)
# => [[ 6 10]
# [ 9 11]]
Чтобы выполнить те же операции над двумя массивами, также не используются циклы. Все синтаксические конструкции остаются без изменений:
# Массив для изменения значений исходного
arr2 = np.array([2, 2, 2, 2, -1, -1, -1, -1])
print(arr1 + arr2)
# => [2 3 4 5 3 4 5 6]
print(arr1 - arr2)
# => [-2 -1 0 1 5 6 7 8]
print(arr1 * arr2)
# => [ 0 2 4 6 -4 -5 -6 -7]
print(arr1 / arr2)
# => [ 0. 0.5 1. 1.5 -4. -5. -6. -7. ]
Для сравнения посмотрим, как выполняются аналогичные задачи над стандартными списками. Без циклов и генератора zip()
в этом случае не обойтись:
arr1 = [0, 1, 2, 3, 4, 5, 6, 7]
change_array_value = 5
arr2 = [2, 2, 2, 2, -1, -1, -1, -1]