Python 中 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 使用原始標量值而不創建副本,因此廣播操作具有內存和計算效率。

一般廣播規則

在兩個數組上運行時,NumPy 會逐元素地比較它們的形狀。它從尾部尺寸開始,並逐漸往前。兩個尺寸兼容時有:

1. 形狀相同

2. 其中一個是1

如果不滿足這些條件,則拋出 ValueError: operands could not be broadcast together 異常,指示數組形狀不兼容。結果數組的大小是輸入數組每一維度的最大值。

數組不需要具有相同數量的維度。例如,如果您有一個 256*256*3 的RGB值數組,並且希望將圖像中的每種顏色縮放不同的值,則可以將圖像乘以具有 3 個值的一維數組。根據廣播規則排列這些數組的尾軸的大小,表明它們是兼容的:

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

當比較的任何一個尺寸爲 1 時,使用另一個尺寸。換句話說,尺寸爲 1 的尺寸被拉伸或“複製”以匹配另一個尺寸。

在以下示例中,A 和 B 數組都具有長度爲 1 的軸,在廣播操作期間會擴展爲更大的大小:

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.]])

廣播提供了一種便捷的方式來獲取兩個數組的外積(或任何其他外部操作)。以下示例顯示了兩個 1-d 數組的外積操作:

>>> 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,使其成爲一個二維 4*1 數組。將 4*1 數組與形狀爲 (3,) 的 b 組合,產生一個 4*3 數組。

參考資料:

1. NumPy 官方文檔:https://numpy.org/devdocs/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章