人工智能之數據分析 numpy

第八章 數組廣播


(文章目錄)


前言

NumPy 的 廣播(Broadcasting) 是其最強大、也最容易被誤解的特性之一。它允許不同形狀的數組之間進行​逐元素運算​,而無需顯式複製數據,既節省內存又提升性能。


一、什麼是廣播?

廣播​:NumPy 在執行算術運算時,自動將形狀不同的數組“擴展”為兼容形狀的機制。

✅ 核心優勢:

  • 避免創建不必要的副本(內存高效)
  • 代碼簡潔(無需手動 reshapetile
  • 運算速度接近 C 語言

二、廣播規則(必須全部滿足)

當兩個數組 AB 進行運算時,從​最後一個維度開始向前對齊​,每個維度需滿足以下之一:

  1. 維度相等​,或
  2. 其中一個維度為 1​,或
  3. 其中一個數組缺少該維度​(即維度數更少)

如果所有維度都滿足,則廣播成功;否則報錯:ValueError: operands could not be broadcast together...


三、廣播示例詳解

示例 1:標量與數組(最簡單)

import numpy as np

a = np.array([1, 2, 3])
b = 10  # 標量 → 視為 shape ()

result = a + b  # [11 12 13]
  • a.shape = (3,)
  • b.shape = () → 自動擴展為 (1,) → 再廣播為 (3,)

示例 2:一維與二維(經典場景)

A = np.array([[1, 2, 3],
              [4, 5, 6]])   # shape (2, 3)
v = np.array([10, 20, 30])   # shape (3,)

C = A + v
print(C)
# [[11 22 33]
#  [14 25 36]]

廣播過程​:

  • 對齊維度:A: (2, 3) vs v: (3,) → 補全為 (1, 3)
  • 比較各維度:
    • 第 1 維:2 vs 1 → 允許(1 可擴展為 2)
    • 第 2 維:3 vs 3 → 相等
  • 結果形狀:(2, 3)

💡 v 被“複製”到每一行,但​沒有實際複製內存​!


示例 3:列向量與行向量

row = np.array([1, 2, 3])      # shape (3,)
col = np.array([[10], [20]])   # shape (2, 1)

result = row + col
print(result)
# [[11 12 13]
#  [21 22 23]]

廣播過程​:

  • row: (3,) → (1, 3)
  • col: (2, 1)
  • 對齊後:
    • 第 1 維:1 vs 2 → 擴展為 2
    • 第 2 維:3 vs 1 → 擴展為 3
  • 結果:(2, 3)

🔥 這是生成網格座標的基礎!


示例 4:三維廣播

A = np.ones((3, 4, 5))
B = np.ones((4, 5))

C = A + B  # 成功!B 被廣播到 (1,4,5) → (3,4,5)

四、廣播失敗的案例

❌ 維度不兼容

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

# a + b → 報錯!
# 維度對齊:(1,2) vs (1,3)
# 最後一維:2 ≠ 3,且都不為1 → 無法廣播

❌ 中間維度衝突

A = np.random.rand(2, 3, 4)
B = np.random.rand(2, 5, 4)

# A + B → 報錯!
# 第2維:3 vs 5 → 無法廣播

五、廣播的實際應用

📌 應用 1:標準化數據(Z-score)

data = np.random.rand(100, 5)  # 100個樣本,5個特徵

# 計算每列均值和標準差
mean = data.mean(axis=0)   # shape (5,)
std = data.std(axis=0)     # shape (5,)

# 標準化:(data - mean) / std
normalized = (data - mean) / std  # 廣播自動對每行操作

📌 應用 2:生成二維網格(用於繪圖)

x = np.linspace(-2, 2, 5)   # [-2 -1 0 1 2] → (5,)
y = np.linspace(-1, 1, 3)   # [-1 0 1]       → (3,)

# 轉為列向量和行向量
X = x[np.newaxis, :]  # shape (1, 5)
Y = y[:, np.newaxis]  # shape (3, 1)

# 廣播生成網格
grid_sum = X + Y
print(grid_sum)
# [[-3. -2. -1.  0.  1.]
#  [-2. -1.  0.  1.  2.]
#  [-1.  0.  1.  2.  3.]]

✅ 這正是 np.meshgrid() 的底層原理!

📌 應用 3:批量矩陣偏移

# 10 個 3x3 矩陣
matrices = np.random.rand(10, 3, 3)

# 一個公共偏移向量(加到每行)
offset = np.array([10, 20, 30])  # (3,)

# 廣播:offset 自動應用到每個矩陣的每一行
result = matrices + offset  # shape (10, 3, 3)

六、如何避免意外廣播?

有時廣播會導致​邏輯錯誤​(如本想矩陣乘法卻做了逐元素乘)。

防禦性編程建議:

  1. 顯式檢查形狀
    assert a.shape == b.shape or ...  # 根據業務邏輯
    
  2. 使用 np.newaxis 明確維度
    # 確保 v 是列向量
    v = v[:, np.newaxis]
    
  3. 慎用高維自動廣播
    # 如果不確定,先 reshape 到預期形狀
    b = b.reshape(1, -1)
    

七、廣播 vs np.tile / np.repeat

方法 內存 速度 推薦
廣播 不復制數據 極快 ✅ 首選
np.tile 創建完整副本 ❌ 僅調試用
np.repeat 創建副本
# 不推薦(浪費內存)
A = np.array([[1, 2], [3, 4]])
B = np.tile([10, 20], (2, 1))  # 顯式複製
C = A + B

# 推薦(廣播)
C = A + [10, 20]  # 自動廣播,無內存開銷

八、總結:廣播速查表

操作 是否廣播 結果形狀
(3,) + () (3,)
(2,3) + (3,) (2,3)
(2,1) + (3,) (2,3)
(2,3) + (2,1) (2,3)
(2,3) + (3,2) 報錯
(4,1,3) + (2,3) (4,2,3)

🧠 ​記憶口訣​:從右往左對齊,1 可擴,等則留,否則錯。


後續

本文主要講述了numpy數組廣播。python過渡項目部分代碼已經上傳至gitee,後續會逐步更新,主要受時間原因限制,當然自己也可以克隆到本地學習拓展。

資料關注

公眾號:咚咚王 gitee:https://gitee.com/wy18585051844/ai_learning

《Python編程:從入門到實踐》 《利用Python進行數據分析》 《算法導論中文第三版》 《概率論與數理統計(第四版) (盛驟) 》 《程序員的數學》 《線性代數應該這樣學第3版》 《微積分和數學分析引論》 《(西瓜書)周志華-機器學習》 《TensorFlow機器學習實戰指南》 《Sklearn與TensorFlow機器學習實用指南》 《模式識別(第四版)》 《深度學習 deep learning》伊恩·古德費洛著 花書 《Python深度學習第二版(中文版)【純文本】 (登封大數據 (Francois Choliet)) (Z-Library)》 《深入淺出神經網絡與深度學習+(邁克爾·尼爾森(Michael+Nielsen)》 《自然語言處理綜論 第2版》 《Natural-Language-Processing-with-PyTorch》 《計算機視覺-算法與應用(中文版)》 《Learning OpenCV 4》 《AIGC:智能創作時代》杜雨+&+張孜銘 《AIGC原理與實踐:零基礎學大語言模型、擴散模型和多模態模型》 《從零構建大語言模型(中文版)》 《實戰AI大模型》 《AI 3.0》