NumPy Essentials for ML
NumPy is the substrate every ML framework is built on. Vectorized operations, broadcasting, axis semantics — the stuff that makes the difference between a fast and a slow model.
Why NumPy matters
PyTorch tensors, TensorFlow tensors, JAX arrays — they all inherit NumPy’s array semantics. Master NumPy and 80% of framework APIs feel familiar.
More importantly: a vectorized NumPy operation is 100-1000× faster than the equivalent Python for-loop. Getting this reflex right early is the single biggest performance skill in data-heavy ML work.
The things that matter
1. Vectorization (not loops)
# Bad: ~100ms for a million elements
result = [x ** 2 for x in data]
# Good: ~1ms
result = np.array(data) ** 2
Every time you write a for-loop over array elements, ask yourself: can I do this with + - * / ** @ and some axis arguments?
2. Broadcasting
NumPy auto-aligns shapes when they’re compatible. A (3, 1) and a (1, 4) broadcast to (3, 4). This is how you vectorize operations between rows and columns without explicit loops.
mean = data.mean(axis=0) # shape (features,)
centered = data - mean # shape (n, features) - (features,) → (n, features)
When broadcasting fails, the error message is your friend. Read the shapes.
3. Axis semantics
axis=0 is “across rows” (producing one value per column). axis=1 is “across columns” (one value per row). Get this backward once and every pipeline bug after will trace back to it.
matrix.sum(axis=0) # column sums, shape (n_cols,)
matrix.sum(axis=1) # row sums, shape (n_rows,)
4. Indexing and slicing
- Basic slicing:
a[1:4],a[:, 2],a[::2]. - Boolean masking:
a[a > 0]. - Fancy indexing:
a[[0, 3, 5]]. reshape,expand_dims,squeeze,transpose— the shape-wrangling quartet.
5. Common operations
np.dot(a, b) # or a @ b — matrix multiply
np.linalg.norm(v) # Euclidean norm
np.argmax(x, axis=-1)
np.where(mask, a, b)
np.concatenate, np.stack, np.split
The gotcha nobody warns you about
np.array([1, 2, 3]).shape is (3,), NOT (3, 1). That trailing comma matters. A “1D row vector” and a “1×3 matrix” are different shapes and will broadcast differently. When in doubt, .reshape(-1, 1) to force 2D.
What to skip
np.matrix — deprecated, use np.ndarray. Most of scipy.ndimage unless you’re doing image work without a DL framework.