06.10 「每天3分鐘學Python」一文總結NumPy的 Broadcast「強烈推薦」

2 Python的 * 和 NumPy的廣播

幾天前,一個小夥伴問:Python的 * 和廣播機制是一回事嗎?它們相似,但實則不同!

1) 先了解下python中的 list * 標量,結果是複製對應的元素,如下所示:

a = [3,8,10]

print(a*3)

[3, 8, 10, 3, 8, 10, 3, 8, 10]

a = [[1,3,2],[6,4,3]]

print(a*2)

[[1, 3, 2], [6, 4, 3], [1, 3, 2], [6, 4, 3]]

list * 標量等於按元素或按行的複製。

2) NumPy 的廣播機制,先看一個例子,如下:

x = np.arange(4)

xx = x.reshape(4,1)

print(xx)

y = np.ones(5)

print(y)

print(xx + y)

xx: array([ [0], [1], [2], [3] ])

y : array([ 1, 1, 1, 1, 1 ])

xx + y : array(array([[ 1., 1., 1., 1., 1.],

[ 2., 2., 2., 2., 2.],

[ 3., 3., 3., 3., 3.],

[ 4., 4., 4., 4., 4.]]) )

上面的例子,xx 的 shape是(4,1),y的 shape(5,),NumPy支持的這類操作,被稱為廣播機制。

3 NumPy廣播 通用規則

注意,不是任意形狀間的ndarray都能做廣播,必須滿足一定的約束條件。對兩個NumPy的 ndarray 進行操作時,NumPy 會比較形狀,開始於最靠後的維度(如5*4*6,最靠後的維度長度是6)。當以下情形出現時,維度是兼容的:

1) 相等

data_2d = np.arange(20).reshape(5,4) # 5 * 4

data_1d = np.array([1,2,3,4]) # 4

print(data_2d * data_1d) # 5 * 4

array([[ 0, 2, 6, 12],

[ 4, 10, 18, 28],

[ 8, 18, 30, 44],

[12, 26, 42, 60],

[16, 34, 54, 76]])

2) 其中一個長度為 1

data_3d = np.arange(20).reshape(5,2,2) # 5 * 2 * 2

data_1d = np.array([3]) # 1

print(data_3d * data_1d) # 5 * 2 * 2

[[[ 0 3]

[ 6 9]]

[[12 15]

[18 21]]

[[24 27]

[30 33]]

[[36 39]

[42 45]]

[[48 51]

[54 57]]]

可以看到,廣播是按照右對齊的方式,其中長度為1的維度被自動廣播。

4 NumPy廣播 好處

先看一個例子。一個ndarray和一個標量相乘,這是廣播機制:

a = np.array([1, 2, 3])

b = 2

print(a * b)

array([2, 4, 6])

如果我們不按照廣播機制,我們可以這樣寫:

a = np.array([1, 2, 3])

b = np.array([2, 2, 2])

print(a * b)

array([2, 4, 6])

標量值 b 在計算時被伸展為 與 a 一樣的形狀,伸展後 b 的每一個元素都是原來標量值的複製。實際上,NumPy 並不需要真的複製這些標量值,所以廣播運算在內存和計算效率上更高效。


分享到:


相關文章: