NumPy廣播(Broadcasting)

另見(jiàn)

Numpy中的數(shù)組廣播

注意

有關(guān)廣播概念的說(shuō)明,請(qǐng)參閱此文章

術(shù)語(yǔ)廣播(Broadcasting)描述了 numpy 如何在算術(shù)運(yùn)算期間處理具有不同形狀的數(shù)組。受某些約束的影響,較小的數(shù)組在較大的數(shù)組上“廣播”,以便它們具有兼容的形狀。廣播提供了一種矢量化數(shù)組操作的方法,以便在C而不是Python中進(jìn)行循環(huán)。它可以在不制作不必要的數(shù)據(jù)副本的情況下實(shí)現(xiàn)這一點(diǎn),通常導(dǎo)致高效的算法實(shí)現(xiàn)。然而,有些情況下廣播是一個(gè)壞主意,因?yàn)樗鼤?huì)導(dǎo)致內(nèi)存使用效率低下,從而減慢計(jì)算速度。

NumPy 操作通常在逐個(gè)元素的基礎(chǔ)上在數(shù)組對(duì)上完成。在最簡(jiǎn)單的情況下,兩個(gè)數(shù)組必須具有完全相同的形狀,如下例所示:

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

當(dāng)數(shù)組的形狀滿足某些約束時(shí),NumPy的廣播規(guī)則放寬了這種約束。當(dāng)一個(gè)數(shù)組和一個(gè)標(biāo)量值在一個(gè)操作中組合時(shí),會(huì)發(fā)生最簡(jiǎn)單的廣播示例:

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

結(jié)果等同于前面的示例,其中b是數(shù)組。我們可以將在算術(shù)運(yùn)算期間b拉伸 的標(biāo)量想象成具有相同形狀的數(shù)組a。新元素
b只是原始標(biāo)量的副本。拉伸類比只是概念性的。NumPy足夠聰明,可以使用原始標(biāo)量值而無(wú)需實(shí)際制作副本,因此廣播操作盡可能具有內(nèi)存和計(jì)算效率。

第二個(gè)示例中的代碼比第一個(gè)示例中的代碼更有效,因?yàn)閺V播在乘法期間移動(dòng)的內(nèi)存較少(b是標(biāo)量而不是數(shù)組)。

一般廣播規(guī)則

在兩個(gè)數(shù)組上運(yùn)行時(shí),NumPy會(huì)逐元素地比較它們的形狀。它從尾隨尺寸開(kāi)始,并向前發(fā)展。兩個(gè)尺寸兼容時(shí)

  1. 他們是平等的,或者
  2. 其中一個(gè)是1

如果不滿足這些條件,則拋出 ValueError: operands could not be broadcast together 異常,指示數(shù)組具有不兼容的形狀。結(jié)果數(shù)組的大小是沿輸入的每個(gè)軸不是1的大小。

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

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

當(dāng)比較的任何一個(gè)尺寸為1時(shí),使用另一個(gè)尺寸。換句話說(shuō),尺寸為1的尺寸被拉伸或“復(fù)制”以匹配另一個(gè)尺寸。

在以下示例中,AB數(shù)組都具有長(zhǎng)度為1的軸,在廣播操作期間會(huì)擴(kuò)展為更大的大?。?/p>

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

實(shí)踐中廣播的一個(gè)例子:

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

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

>>> 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 索引操作符插入一個(gè)新軸 a ,使其成為一個(gè)二維 4x1 數(shù)組。將 4x1 數(shù)組與形狀為 (3,)b 組合,產(chǎn)生一個(gè)4x3數(shù)組。

作者:柯廣的網(wǎng)絡(luò)日志 ? NumPy廣播(Broadcasting)


微信公眾號(hào):Java大數(shù)據(jù)與數(shù)據(jù)倉(cāng)庫(kù)