A001.广播机制
文章目录
问题: 谈谈NumPy的广播机制
👇 点击展开/折叠 面试背诵模板(建议先背这个)
1. 抛弃“行和列”,记住“括号的层数”
Shape(形状)的本质:它是一个元组(tuple),元组里有几个数字,就代表这个数组是几维的(几层括号)。每个数字代表那一层括号里装了几个小格子。
灵魂口诀:“看括号,数格子,从外往里数层级。”
我们直接看代码截图(脑补 + 文本示意图):
一维数组(1个维度)
1 | arr = np.array([1, 2, 3, 4]) |
示意图:
1 | [ 1, 2, 3, 4 ] ← 最外层(也是唯一一层)括号里,装了 4 个数 |
理解:
shape=(4,)表示“这一排有4个格子”。
二维数组(2个维度)—— 你最熟悉的矩阵
1 | arr = np.array([[1, 2, 3], |
手绘解剖图:
1 | 第0层(最外层括号) |
- 维度0(最外层):里面装了 2 个大块(两行) →
shape[0] = 2 - 维度1(内层):每个大块里面装了 3 个小块(三列) →
shape[1] = 3
理解:
shape=(2, 3)就是“外层有2个组,每个组里有3个元素”。
三维数组(3个维度)—— 这才是广播的真正战场!
比如 shape=(4, 3, 2),很多人看到就晕,其实剥开看特别简单:
1 | # 假装这是一个 4页纸,每页3行,每行2列 的数据 |
手绘结构图(套娃):
1 | 最外层括号(维度0)里,有 4 个大箱子 → shape[0] = 4 |
- 维度0(最外层):有 4 页 →
shape[0]=4 - 维度1(中间层):每页有 3 行 →
shape[1]=3 - 维度2(最内层):每行有 2 个数 →
shape[2]=2
2. 维度索引是怎么数的?(轴 Axis)
记住:索引 0 永远是最外层的括号,索引 1 是往里一层……
| shape 元组 | 维度0(轴0) | 维度1(轴1) | 维度2(轴2) |
|---|---|---|---|
(4,) |
4个数 | — | — |
(3, 2) |
3行(大组) | 2列(小组) | — |
(2, 3, 4) |
2个块(最外层) | 每个块里3行 | 每行里4个数 |
极简记忆:
shape从左到右,就是 “从大到小” 的容器嵌套关系。
3. 回过头看“广播”,为什么规则是从右往左对齐?
因为广播比较的是“最里层”的小单元能否对上!
想象两个数组要相加:
- 数组A:
shape = (4, 3)—— 4行3列。 - 数组B:
shape = (3,)—— 只有一排(3个数)。
套娃对齐法(从右往左):
先把两个形状右对齐写出来:
1
2A : 4 3
B : 3从最右边(最小的格子)往左看:
- 先看最里层(维度1):A是3,B是3 → 相等 ✅
- 再看外层(维度0):A是4,B没有(视为1) → 有1 ✅(B的这一层只有1个,可以复印成4份)
所以能广播!B 的最外层那个隐藏的 1 被复制成了 4 份。
4. 颠覆你认知的一句话(反复读三遍)
shape里数字的个数(元组长度)叫“维数”,数字本身叫“该维的长度”。
一维数组(3,)和二维数组(1, 3)在广播眼里是平级的,因为广播时会自动给(3,)左边补个1变成(1, 3)。
5. 终极实操检查表(以后看 shape 就这么干)
拿到一个 shape,比如 (2, 1, 4):
- 有多少维? → 3维(因为元组里有3个数字)。
- 最外层多大? →
2(有2个大组)。 - 中间层多大? →
1(每个大组里只有1个中间组,这个维度以后可以被广播复制!)。 - 最里层多大? →
4(每个中间组里有4个小数据)。
6. 给你一个“灵魂图像”印在脑子里
- 标量
():就是一个孤零零的点(0维)。 - 向量
(5,):一条线上排了5个点(1维)。 - 矩阵
(3, 5):一张纸上画了3行5列的网格(2维)。 - 立方体
(4, 3, 5):一个长方体书架上,有4层,每层3排,每排5本书(3维)。
当广播发生时,就是把这个书架上“只有1排”的隔板,复印成跟对方一样多的排数。
一句话,广播的本质
形状不同的数组做运算时,NumPy 会自动把“维度为 1”的那一方,沿该维度“复制”成与另一方相同的长度,然后逐个元素计算。
重点:复制只发生在维度值为 1 的轴上,不是随便复制。
最管用的判断方法——从右往左对维度(记住这个就行)
步骤:
- 把两个数组的
shape从最右边(末维)往左看。 - 对应维度比较:
- 如果相等 ✅
- 如果其中一个等于
1✅(这个1会被拉伸) - 否则 ❌ 报错
输出形状: 对应维度取两者中的最大值。
立刻实战验证(用你的例子)
| 数组 | shape | 从右往左看 |
|---|---|---|
a |
(4,3) | 末维是3,次维是4 |
b |
(3,) | 末维是3,次维没有(看作1) |
- 末维:3 vs 3 → 相等 ✅
- 次维:4 vs 1 → 有1 ✅
→ 可广播!输出形状(max(4,1), max(3,3)) = (4,3)。
(b的次维1被拉伸成4,末维3保持不变)
再试一个报错的
| 数组 | shape |
|---|---|
a |
(3,2) |
b |
(2,3) |
从右往左:
- 末维:2 vs 3 → 不等,且无1 ❌ → 直接报错。
回到你写的“复印”比喻,稍微修正一下表述
你写“向下复制”、“向右复制”都很形象,但要指明复制方向:
- 行向量
(1, N)→ 沿行方向(纵向)复制成(M, N) - 列向量
(M, 1)→ 沿列方向(横向)复制成(M, N) - 标量
(1,)→ 两个方向都复制
你只要记住:哪个轴长度是1,就沿着那个轴复制,直到匹配对方长度。
终极偷懒口诀(送给你)
“右对齐,逐个比,相等或1就能行;输出取大值,1被拉伸。”
太棒了!学完立马实战是掌握最快的方式。
我给你准备了 “6道闯关题”,从易到难,最后一题是陷阱题。你先别偷看答案,拿出草稿纸,按照我们刚教的 “从右往左对维度,有1就复印” 的规则,算出 “能否广播” 以及 “输出形状是什么”。
📝 闯关测试题(共6题)
请写出:① 能否广播?(能/不能) ② 如果能,输出的 Shape 是什么?
第1题(热身题)
1 | a.shape = (6, 5) |
👉 你的答案:能不能?输出形状?
第2题(送分题)
1 | a.shape = (3, 1) |
👉 你的答案:能不能?输出形状?
第3题(横向拉伸)
1 | a.shape = (4, 1, 6) |
👉 你的答案:能不能?输出形状?
第4题(同时拉伸——经典3x3矩阵)
1 | a.shape = (3, 1) |
👉 你的答案:能不能?输出形状?
第5题(高维挑战)
1 | a.shape = (2, 3, 4, 5) |
👉 你的答案:能不能?输出形状?
第6题(大坑预警——必错题)
1 | a.shape = (3, 2) |
👉 你的答案:能不能?输出形状?
🛑 我是分割线,做完之前不许往下看!🛑
✅ 答案与深度解析(交卷后来对)
第1题答案
- 能广播 ✅
- 输出形状:
(6, 5) - 解析:右对齐。最右列 5==5(相等);左边 a是6,b是空(视为1)。有1,复制成6。
1
2a: 6 5
b: 5
第2题答案
- 能广播 ✅
- 输出形状:
(3, 3)(注意!不是 (3,1)!) - 解析:先把 b 的
(3,)左边补1变成(1, 3)。最右列:1 vs 3 → 有1,复制成3(b的列复制成3列)。1
2a: 3 1
b: 1 3
左列:3 vs 1 → 有1,复制成3(a的行复制成3行)。
结果:两者都拉伸,变成(3, 3)大方阵。
第3题答案
- 能广播 ✅
- 输出形状:
(4, 1, 6)(注意,虽然能算,但输出形状以a为准,中间的1保留) - 解析:先把 b 的
(1, 6)左边补1变成(1, 1, 6)。从右往左:6==6(相等);1==1(相等);4 vs 1(有1,复制成4)。1
2a: 4 1 6
b: 1 1 6
因为 a 的中间维度是1,b 的中间维度也是1,输出取最大值,还是1。
第4题答案
- 能广播 ✅
- 输出形状:
(3, 3) - 解析:这是经典的行向量+列向量,会变成一个大方块。右列 1 vs 3(有1,b复制成3列);左列 3 vs 1(有1,a复制成3行)。变成 3x3。
1
2a: 3 1
b: 1 3
第5题答案
- 能广播 ✅
- 输出形状:
(2, 3, 4, 5) - 解析:先把 b 的
(3, 1, 5)左边补1变成(1, 3, 1, 5)。从右往左:5==5;4 vs 1(有1,b复制成4);3==3;2 vs 1(有1,b复制成2)。1
2a: 2 3 4 5
b: 1 3 1 5
完美匹配,输出取最大值:(2, 3, 4, 5)。
第6题答案
不能广播 ❌(报错!)
解析:这是最容易掉坑的地方,看着都是2和3,但位置不对!
1
2a: 3 2
b: 2 3从右往左看(先看列):
最右边:2 vs 3 → 既不相等,也没有1。
NumPy 直接翻脸,报错:operands could not be broadcast together with shapes (3,2) (2,3)