9.10. Broadcasting¶
When a binary operator gets two arrays whose shapes do
not match exactly, numpy does not raise – it
broadcasts. Broadcasting is a small set of rules that
decide whether two shapes are compatible and, if they
are, how the smaller one is virtually stretched to match
the larger.
9.10.1. The rules¶
There are two:
If the two operands have different rank, virtually prepend size-1 axes to the lower-rank operand until both ranks match.
Along each axis, the two sizes must be equal or one of them must be 1. A size-1 axis is virtually stretched to match the other side.
If neither rule applies, numpy raises
ValueError:
ValueError: operands could not be broadcast together
9.10.2. Worked shapes¶
Scalar against any array. The scalar’s shape is
effectively (1,), which trivially broadcasts:
a = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float)
a + 10 # (2, 3) + scalar -> (2, 3)
1-D vector against a 2-D matrix. After rule 1 the vector is treated as a 1-row matrix, then rule 2 stretches that row down each column:
row = np.array([100, 200, 300], dtype=np.float)
a + row # (2, 3) + (3,) -> (2, 3)
Two 1-D arrays of equal length broadcast element-wise:
np.arange(4) + np.arange(4)
Column vector against a row vector produces an outer result – rule 2 stretches both inputs to a 2-D shape:
x = np.array([1, 2, 3, 4]).reshape((4, 1)) # column
y = np.array([10, 20, 30]) # row
x + y # (4, 3) matrix
These also work through two-argument ufuncs like
arctan2():
np.arctan2(y, 1.0)
np.arctan2(y, x)
9.10.3. What broadcasting does not allocate¶
The stretch is virtual. numpy walks both
operands together, re-reading the smaller one along
its broadcast axis instead of copying it. The shorter
array’s data is never replicated in memory.
The size of the output array is what matters for
memory. a + row allocates an output the shape of
a, not the shape of a plus the shape of
row. Long broadcasting chains can still produce
large intermediates – the Performance page
covers how to keep those allocations down.
9.10.4. When two shapes cannot broadcast¶
Mismatches that the rules cannot resolve raise
ValueError at the call site. Two common shapes
that fail:
(3, 4)against(4, 3)– neither axis is size 1, and the corresponding sizes disagree.(5,)against(5, 1)after the rank prepend gives(1, 5)against(5, 1), which broadcasts to(5, 5). If that is what the application meant, fine; if the intent was element-wise on length 5, one of the arrays needs reshaping first.
When in doubt, print
shape on both sides and step
through the rules above before reaching for
reshape() or
transpose().