Векторная арифметика и where/clip
Содержание курса
Поэлементные арифметические операции над массивами
Когда вы пишете a + b для двух массивов NumPy одинаковой формы, сложение происходит не как «сложить два объекта», а как «сложить каждый элемент a с соответствующим элементом b». Так работают все стандартные операторы: +, -, *, /, //, **, %.
import numpy as np
a = np.array([10, 20, 30, 40])
b = np.array([3, 4, 5, 6])
print(a + b) # [13 24 35 46]
print(a - b) # [ 7 16 25 34]
print(a * b) # [ 30 80 150 240]
print(a / b) # [3.333... 5.0 6.0 6.666...]
print(a // b) # [3 5 6 6]
print(a ** 2) # [ 100 400 900 1600]
print(a % b) # [1 0 0 4]
Несколько моментов, на которые стоит обратить внимание.
/ выполняет true division. Для обычных целочисленных массивов (как int64 в примере выше) результат — вещественный массив float64. Это отличает / от //: np.array([10]) / np.array([3]) даёт [3.333...], а не [3]. Для вещественных и комплексных dtype конкретный тип результата определяется правилами promotion — например, float32 / float32 остаётся float32.
// — floor division, то есть частное округляется вниз до ближайшего целого. Для положительных чисел это совпадает с обычным усечением, но для отрицательных — нет: np.array([-7]) // np.array([2]) даст [-4], а не [-3].
Исходные массивы не изменяются. Любая операция возвращает новый массив — a и b остаются нетронутыми.
Тип результата определяется dtype операндов по правилам promotion. Два int64-массива при сложении, вычитании или умножении дадут int64; если один из операндов float64 — результат будет float64. NumPy выбирает тип автоматически, и явное приведение типов нужно редко.
Операции со скаляром работают так же — скаляр применяется к каждому элементу:
print(a * 2) # [20 40 60 80]
print(a + 100) # [110 120 130 140]
Это именно то, что делает NumPy быстрее Python-цикла: вместо последовательного обхода элементов вся операция выполняется на уровне скомпилированного кода за один вызов.
