Broadcasting
Broadcasting is how NumPy combines arrays of different shapes. You've used it already: a * 2 multiplies every element by 2, because the single number is stretched to match the array.
A row across every row
import numpy as np
prices = np.array([[10.0, 20.0, 30.0],
[15.0, 25.0, 35.0]])
tax = np.array([0.05, 0.12, 0.18]) # one rate per column
print(prices * (1 + tax))tax has shape (3,) and prices (2, 3). NumPy repeats tax for each row, without actually copying it, so every column gets its own rate.
A column across every column
import numpy as np
prices = np.array([[10.0, 20.0, 30.0],
[15.0, 25.0, 35.0]])
discount = np.array([[0.10], # shape (2, 1): one value per row
[0.50]])
print(prices * (1 - discount))The rules
NumPy compares the shapes from the right. Two dimensions are compatible when they're equal, or when one of them is 1, which gets stretched:
| Shape A | Shape B | Result |
|---|---|---|
(2, 3) | (3,) | (2, 3) |
(2, 3) | (2, 1) | (2, 3) |
(3, 1) | (1, 4) | (3, 4) |
(2, 3) | (2,) | error: 3 and 2 don't match |
import numpy as np
a = np.ones((2, 3))
b = np.array([1, 2]) # shape (2,)
print(a + b) # ValueError: shapes (2,3) and (2,) can't broadcastTo add b to each row, it needs to be a column, shape (2, 1): a + b[:, np.newaxis] works.
Building a table: an outer product
import numpy as np
n = np.arange(1, 6)
table = n[:, np.newaxis] * n # (5, 1) times (5,) gives (5, 5)
print(table)A column times a row gives every combination: a multiplication table with no loops.
Normalising columns
A real use: rescale each column to have mean 0 and standard deviation 1, so that columns measured in different units become comparable:
import numpy as np
# height in cm, weight in kg, age in years
data = np.array([[170.0, 65.0, 21.0],
[182.0, 80.0, 35.0],
[158.0, 52.0, 28.0],
[175.0, 73.0, 42.0]])
means = data.mean(axis=0) # shape (3,): one mean per column
stds = data.std(axis=0)
scaled = (data - means) / stds # (4, 3) with (3,): broadcast down the rows
print(np.round(scaled, 2))
print(np.round(scaled.mean(axis=0), 10)) # every column now has mean 0Distances from a point
import numpy as np
shops = np.array([[2.0, 3.0],
[5.0, 1.0],
[1.0, 7.0],
[6.0, 6.0]])
home = np.array([3.0, 4.0])
distances = np.sqrt(((shops - home) ** 2).sum(axis=1))
print(np.round(distances, 2))
print("nearest shop:", distances.argmin())shops - home subtracts the same point from every row in one step.