Chapter 3 · Part 2
Vectorized math & broadcasting
Here's why NumPy exists. In plain Python, doing math on a list means writing a loop. In NumPy you operate on the whole array at once — it's shorter, clearer, and runs far faster because the looping happens in optimized C under the hood. This is called vectorization.
Math on whole arrays
Arithmetic and math functions apply element by element, automatically:
v = np.array([10, 20, 30, 40, 50])
v * 2 + 1 # [ 21 41 61 81 101] — no loop needed
np.sqrt([1, 4, 9, 16]) # [1. 2. 3. 4.]
np.exp([0, 1]) # [1. 2.7182818]Compare that to the Python you didn't have to write — [x * 2 + 1 for x in v]. One array
expression replaces the loop, and it stays fast even on a million elements.
Broadcasting: stretching shapes to fit
What happens when shapes don't match? NumPy broadcasts — it stretches the smaller array
across the larger one so they line up. The simplest case you've already seen: v * 2 stretches
the scalar 2 across every element. It also works between arrays:
col = np.array([[1],
[2],
[3]]) # shape (3, 1) — a column
row = np.array([10, 20, 30]) # shape (3,) — a row
col + row
# [[11 21 31]
# [12 22 32]
# [13 23 33]]The (3, 1) column and the (3,) row stretch against each other to fill a full (3, 3) grid —
every combination, computed at once. That's the whole idea: line up shapes, stretch the
size-1 dimensions.
Vectorization and broadcasting are the heart of NumPy. Next: boiling arrays down to summaries.