Spec-Zone.ru › NumPy 1.21

Вещание

См. также

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–2021 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/1.20/user/basics.broadcasting.html

Spec-Zone.ru

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