(九)从对应位置推导广播
1. 一份列偏移应用到每天
现在给早上加 1、晚上加 2。我们需要把 [1,2] 同时用于三天,每个结果仍有三行两列:
# 项目文件:demos/broadcast.py
# 先按末尾轴对齐:每列补偿用长度 2,每行补偿先变成三行一列。
import numpy as np
a = np.array([[10, 20], [30, 40], [50, 60]])
column_offsets = np.array([1, 2])
row_offsets = np.array([100, 200, 300])
print("每列", (a + column_offsets).tolist())
try:
a + row_offsets
except ValueError:
print("(3,2)与(3,)末尾2和3不匹配")
print("每行", (a + row_offsets[:, None]).tolist())
print("两边扩展", (np.array([1, 2, 3])[:, None] + np.array([10, 20])).tolist())形状从右往左对齐:(3,2) 与 (2,) 对齐时,最后一轴都是 2;缺少的前轴按长度 1 参与匹配,成为 (1,2),再扩展到三行。结果为 [[11,22],[31,42],[51,62]]。
这类按照形状对齐的计算叫 广播。对应轴长度相等,或其中一边长度为 1,就能匹配。广播过程中可以重复读取同一份偏移,不必预先复制出三份偏移数组。广播规则
2. 每天的偏移需要保留列轴
若要给三天分别加 100、200、300,(3,) 会先与最后的时段轴 2 对齐,3 与 2 不匹配。把它变成 row_offsets[:,None],shape 为 (3,1):天轴 3 与 3 对齐,时段轴 1 扩展到 2。
于是得到 [[110,120],[230,240],[350,360]]。修正的依据是“同一天两项共用同一个偏移”,由这个对应关系决定在哪个位置插轴。
3. 输出数组也要计算大小
(3,1) 与 (2,) 还可以共同展开为 (3,2),生成全部行列组合。若两个长度都为一百万,把它们改成列与行后相加,输出就有一万亿项;float64 元素数据约占 8 TB。广播能省去输入的重复复制,结果数组与中间数组仍然需要空间。较大的组合计算可以分批,后面用小批累计展示这种组织方式。