Spec-Zone.ru › NumPy 1.19

Вещание

См. также

numpy.broadcast

Вещание массивов в NumPy

Вступление к обсуждаемым здесь понятиям

Примечание

См. эту статью для иллюстраций понятий вещания.

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

Операции NumPy обычно выполняются попарно над массивами на элементно-базовой основе. В простейшем случае два массива должны иметь точно одинаковую форму, как в следующем примере:

>>> a = np.array([1.0, 2.0, 3.0])
>>> b = np.array([2.0, 2.0, 2.0])
>>> a * b
array([ 2.,  4.,  6.])

Правило вещания NumPy ослабляет это ограничение, когда формы массивов соответствуют определённым ограничениям. Простейший пример вещания возникает, когда массив и скалярное значение комбинируются в операции:

>>> a = np.array([1.0, 2.0, 3.0])
>>> b = 2.0
>>> a * b
array([ 2.,  4.,  6.])

Результат эквивалентен предыдущему примеру, где b был массивом. Мы можем представить, что скаляр b растягивается во время арифметической операции в массив с такой же формой, как a. Новые элементы в b просто представляют копии исходного скаляра. Аналогия с растяжением — только концептуальна. NumPy достаточно умен, чтобы использовать исходное скалярное значение без фактического создания копий, так что операции вещания максимально эффективны с точки зрения памяти и вычислений.

Код во втором примере более эффективен, чем в первом, потому что вещание перемещает меньше памяти во время умножения (b является скалярным значением, а не массивом).

Общие правила вещания

При работе с двумя массивами NumPy сравнивает их формы поэлементно. Он начинает с последующих измерений и идёт вперёд. Два измерения совместимы, когда

  1. они равны, или
  2. одно из них равно 1

Если эти условия не выполняются, выбрасывается исключение ValueError: operands could not be broadcast together, указывая, что формы массивов несовместимы. Размер результирующего массива — размер, который не равен 1 вдоль каждой оси входных данных.

Массивы не обязательно должны иметь одинаковое количество измерений. Например, если у вас есть 256x256x3 массив значений RGB, и вы хотите масштабировать каждый цвет на изображении на разное значение, вы можете умножить изображение на одномерный массив с 3 значениями. Сопоставление размеров последующих осей этих массивов в соответствии с правилами вещания показывает, что они совместимы:

Image  (3d array): 256 x 256 x 3
Scale  (1d array):             3
Result (3d array): 256 x 256 x 3

Когда одно из сравниваемых измерений равно единице, используется другое. Другими словами, измерения с размером 1 растягиваются или «копируются», чтобы соответствовать другому.

В следующем примере и A, и B массивы имеют оси длиной один, которые расширяются до большего размера во время операции вещания:

A      (4d array):  8 x 1 x 6 x 1
B      (3d array):      7 x 1 x 5
Result (4d array):  8 x 7 x 6 x 5

Вот ещё несколько примеров:

A      (2d array):  5 x 4
B      (1d array):      1
Result (2d array):  5 x 4

A      (2d array):  5 x 4
B      (1d array):      4
Result (2d array):  5 x 4

A      (3d array):  15 x 3 x 5
B      (3d array):  15 x 1 x 5
Result (3d array):  15 x 3 x 5

A      (3d array):  15 x 3 x 5
B      (2d array):       3 x 5
Result (3d array):  15 x 3 x 5

A      (3d array):  15 x 3 x 5
B      (2d array):       3 x 1
Result (3d array):  15 x 3 x 5

Вот примеры форм, которые не вещаются:

A      (1d array):  3
B      (1d array):  4 # trailing dimensions do not match

A      (2d array):      2 x 1
B      (3d array):  8 x 4 x 3 # second from last dimensions mismatched

Пример вещания на практике:

>>> x = np.arange(4)
>>> xx = x.reshape(4,1)
>>> y = np.ones(5)
>>> z = np.ones((3,4))

>>> x.shape
(4,)

>>> y.shape
(5,)

>>> x + y
ValueError: operands could not be broadcast together with shapes (4,) (5,)

>>> xx.shape
(4, 1)

>>> y.shape
(5,)

>>> (xx + y).shape
(4, 5)

>>> xx + y
array([[ 1.,  1.,  1.,  1.,  1.],
       [ 2.,  2.,  2.,  2.,  2.],
       [ 3.,  3.,  3.,  3.,  3.],
       [ 4.,  4.,  4.,  4.,  4.]])

>>> x.shape
(4,)

>>> z.shape
(3, 4)

>>> (x + z).shape
(3, 4)

>>> x + z
array([[ 1.,  2.,  3.,  4.],
       [ 1.,  2.,  3.,  4.],
       [ 1.,  2.,  3.,  4.]])

Вещание обеспечивает удобный способ взятия внешнего произведения (или любой другой внешней операции) двух массивов. Следующий пример демонстрирует внешнюю операцию сложения двух одномерных массивов:

>>> a = np.array([0.0, 10.0, 20.0, 30.0])
>>> b = np.array([1.0, 2.0, 3.0])
>>> a[:, np.newaxis] + b
array([[  1.,   2.,   3.],
       [ 11.,  12.,  13.],
       [ 21.,  22.,  23.],
       [ 31.,  32.,  33.]])

Здесь оператор newaxis вставляет новую ось в a, делая его двумерным 4x1 массивом. Объединение 4x1 массива с b, который имеет форму (3,), даёт 4x3 массив.

© 2005–2020 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/1.19/user/basics.broadcasting.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API