在使用Numpy處理數組時,我們經常需要對不同形狀的數組進行運算。比如,給一個二維數組的每個元素加一個常數,或者計算兩個形狀不同的數組的和。這時候,Numpy的廣播機制就能派上用場,它能讓我們用最簡單的方式完成這些操作,而不用手動調整數組形狀。

爲什麼需要廣播機制?

想象一下,如果沒有廣播機制,當我們想對一個二維數組的每個元素加一個常數時,可能需要先把這個常數擴展成和數組形狀相同的數組,再進行相加。例如,有一個2行3列的數組:

import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6]])
constant = 10

如果沒有廣播,我們可能需要先把constant變成和arr形狀相同的數組:

# 手動擴展常數爲2行3列
constant_arr = np.array([[10, 10, 10], [10, 10, 10]])
result = arr + constant_arr

這顯然很繁瑣。而廣播機制的核心就是自動完成這種形狀的擴展,讓我們可以直接寫arr + 10就能得到正確的結果,無需手動處理。

什麼是廣播機制?

廣播(Broadcasting)是Numpy中一種強大的功能,它允許形狀不同的數組之間進行元素級運算。它的核心思想是:當兩個數組的形狀在某些維度上不匹配時,Numpy會自動將較小的數組“擴展”到與較大數組相同的形狀,使得它們可以兼容運算

這種“擴展”不是真正地在內存中複製數組,而是通過邏輯上的重複來實現,因此不會額外消耗太多內存,反而能提高運算效率。

廣播的核心規則

廣播的關鍵是“兼容”。要滿足以下規則,兩個數組才能進行廣播:

  1. 從右到左匹配維度:Numpy會從數組形狀的最右側維度開始,依次向左匹配。
  2. 維度大小兼容:如果一個數組在某個維度上的大小是1,或者兩個數組在該維度上的大小相等,則認爲這兩個維度兼容。
  3. 擴展到最大維度:較小的數組會被“廣播”到與較大數組相同的形狀,具體是在較小數組的前面添加維度,或者在已有維度上重複。

實例講解:廣播如何工作

1. 標量與數組的廣播

標量(0維數組)可以廣播到任何形狀的數組。例如,給數組的每個元素加一個常數:

arr = np.array([[1, 2, 3], [4, 5, 6]])
result = arr + 10  # 標量10會被廣播到arr的形狀
print(result)

輸出:

[[11 12 13]
 [14 15 16]]

2. 一維數組與二維數組的廣播

假設我們有一個2行3列的二維數組arr,和一個長度爲3的一維數組b

arr = np.array([[1, 2, 3], [4, 5, 6]])  # shape: (2, 3)
b = np.array([10, 20, 30])             # shape: (3,)
result = arr + b                       # 一維數組b會被廣播到(2, 3)
print(result)

這裏,b的形狀是(3,),而arr的形狀是(2, 3)。根據廣播規則:
- 從右到左匹配:b的最後一個維度大小是3,arr的最後一個維度大小也是3,因此兼容。
- b會被“擴展”到arr的形狀,即b會被重複爲2行3列的數組:[[10,20,30], [10,20,30]]
- 相加後結果是:

[[11 22 33]
 [14 25 36]]

3. 更高維度數組的廣播

如果有一個三維數組和一個二維數組,廣播規則同樣適用。例如:

arr3d = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])  # shape: (2, 2, 2)
arr2d = np.array([[10, 20], [30, 40]])                  # shape: (2, 2)
result = arr3d + arr2d  # arr2d會被廣播到(2, 2, 2)
print(result)

這裏,arr2d的形狀是(2, 2),arr3d的形狀是(2, 2, 2)。廣播時:
- 從右到左匹配:arr2d的最後兩個維度是(2, 2),arr3d的最後兩個維度也是(2, 2),因此兼容。
- arr2d會被擴展爲(1, 2, 2),然後再在最前面添加一個維度(因爲arr3d有3個維度,arr2d只有2個),變成(2, 2, 2)。
- 最終相加結果是每個3D數組的每個元素加上對應的2D數組元素。

不兼容的情況:廣播錯誤

廣播並非萬能的。如果兩個數組在某個維度上的大小不兼容(即不是1也不相等),Numpy會報錯。例如:

arr1 = np.array([[1, 2], [3, 4]])  # shape: (2, 2)
arr2 = np.array([[10, 20, 30]])   # shape: (1, 3)
result = arr1 + arr2  # 報錯!

這裏,arr1的形狀是(2, 2),arr2的形狀是(1, 3)。從右到左匹配:
- arr1的最後一個維度是2,arr2的最後一個維度是3,兩者不兼容(既不是1也不相等)。
- 因此,Numpy會拋出ValueError: operands could not be broadcast together with shapes (2,2) (1,3)

廣播的實際應用

廣播機制讓數組運算變得極其簡潔,常見應用場景包括:

  • 元素級操作:給數組所有元素加/減/乘/除一個常數(如arr + 5)。
  • 矩陣標準化:對每個元素減去均值(均值是標量,會廣播到整個數組)。
  • 避免循環:例如計算每個元素的平方、或與另一個數組的對應元素相乘,無需手動寫循環。

總結

廣播機制是Numpy的核心特性之一,它讓不同形狀的數組可以無縫進行元素級運算,極大簡化了代碼,同時避免了內存浪費。關鍵記住:

  1. 廣播的核心是“自動擴展小維度數組到與大維度數組相同的形狀”。
  2. 規則:從右到左匹配維度,每個維度大小必須是1或相等。
  3. 應用:避免手動reshape,直接寫簡潔的數組運算。

掌握廣播機制後,你會發現處理Numpy數組時效率會大幅提升,代碼也更簡潔易讀。

練習:嘗試用廣播計算arr = np.array([1, 2, 3])的每個元素的立方,以及arr = np.array([[1, 2], [3, 4]])b = np.array([10, 20])相加的結果。

小夜