Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ageron/handson-ml3/llms.txt

Use this file to discover all available pages before exploring further.

NumPy is the fundamental library for scientific computing in Python. Its core contribution is the ndarray — an N-dimensional array object that enables fast, vectorized numerical operations. Every ML notebook in this series depends on NumPy, from loading data to computing gradients. Understanding NumPy well saves you from slow Python loops and enables you to work efficiently with the large matrices that appear throughout machine learning.

Creating arrays

The most common way to import NumPy is:
import numpy as np

np.zeros, np.ones, np.full

Create arrays filled with a constant value.
np.zeros(5)
# array([0., 0., 0., 0., 0.])

np.zeros((3, 4))   # 3x4 matrix of zeros
np.ones((3, 4))    # 3x4 matrix of ones
np.full((3, 4), np.pi)   # 3x4 matrix of π

Array shape vocabulary

Every array has a shape, ndim, and size:
a = np.zeros((3, 4))

a.shape   # (3, 4)
a.ndim    # 2  — equal to len(a.shape)
a.size    # 12 — total number of elements (3*4)
Each dimension is called an axis. The number of axes is the rank. A rank-2 array is a matrix; a rank-3 array is a 3D block of numbers.

np.arange and np.linspace

np.arange works like Python’s range, while np.linspace is safer for floats because it guarantees an exact count of elements:
np.arange(1, 5)        # array([1, 2, 3, 4])
np.arange(1, 5, 0.5)   # array([1., 1.5, 2., 2.5, 3., 3.5, 4., 4.5])

np.linspace(0, 5/3, 6)
# [0.         0.33333333 0.66666667 1.         1.33333333 1.66666667]
Prefer np.linspace over np.arange whenever you work with floats. Floating-point rounding in arange can produce one more or one fewer element than expected, leading to hard-to-debug shape mismatches.

Random arrays

NumPy’s random module is used throughout the ML notebooks to generate synthetic data and initialise weights:
np.random.rand(3, 4)    # uniform [0, 1), shape (3, 4)
np.random.randn(3, 4)   # standard normal (mean=0, std=1), shape (3, 4)

Indexing and slicing

NumPy arrays support standard Python slicing notation, extended to multiple dimensions:
a = np.array([[1, 2, 3, 4], [10, 20, 30, 40]])

a[0]        # first row:  array([1, 2, 3, 4])
a[1, 2]     # row 1, col 2: 30
a[:, 1]     # all rows, column 1: array([ 2, 20])
a[0, 1:3]   # row 0, cols 1 and 2: array([2, 3])
Boolean indexing filters elements that satisfy a condition:
a[a > 5]   # array([10, 20, 30, 40])

Broadcasting

Broadcasting is NumPy’s mechanism for performing element-wise operations on arrays with different shapes without copying data. The rule is: dimensions are compared from the trailing (rightmost) axis. Two dimensions are compatible if they are equal or one of them is 1.
a = np.array([[1, 2, 3], [4, 5, 6]])   # shape (2, 3)
b = np.array([10, 20, 30])             # shape (3,) — broadcast over rows

a + b
# array([[11, 22, 33],
#        [14, 25, 36]])
Broadcasting rules in full: (1) arrays are padded with size-1 axes on the left until they have the same rank; (2) axes of size 1 are stretched to match the other array. An error is raised only when two non-1 axis sizes differ.

Vectorized math operations

NumPy operations apply element-wise by default; no loops required:
x = np.linspace(-2, 2, 500)
y = x ** 2          # element-wise square

np.sqrt(a)          # element-wise square root
np.exp(a)           # element-wise exponential
np.log(a)           # element-wise natural log
np.abs(a)           # absolute value
Aggregation functions reduce an array along one or more axes:
a.sum()             # sum of all elements
a.mean(axis=0)      # mean along axis 0 (column means)
a.max(axis=1)       # max along axis 1 (row maxes)
a.std()             # standard deviation

Dot products and matrix multiplication

The @ operator (available since Python 3.5 / NumPy 1.10) computes matrix products and dot products. np.dot does the same:
u = np.array([2, 5])
v = np.array([3, 1])

u @ v               # dot product: 2*3 + 5*1 = 11
np.dot(u, v)        # same result: 11

A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

A @ B               # matrix multiplication
# array([[19, 22],
#        [43, 50]])

np.linalg — linear algebra utilities

The numpy.linalg module provides the core linear-algebra operations used in ML:
import numpy.linalg as LA

u = np.array([2, 5])
LA.norm(u)             # Euclidean norm ≈ 5.385

A = np.array([[3., 1.], [1., 3.]])
LA.inv(A)              # matrix inverse
LA.det(A)              # determinant

eigenvalues, eigenvectors = LA.eig(A)

U, s, Vt = LA.svd(A)  # singular value decomposition (used in PCA)

Reshaping and transposing

a = np.arange(12)

a.reshape(3, 4)    # view as 3x4 matrix
a.reshape(2, 2, 3) # view as 3D array

A = np.array([[1, 2, 3], [4, 5, 6]])
A.T                # transpose: shape (3, 2)

Converting to/from Python lists

python_list = [[1, 2], [3, 4]]
arr = np.array(python_list)   # Python list → ndarray

arr.tolist()                  # ndarray → Python list
In the notebooks, arr.to_numpy() appears on Pandas DataFrames and Series — that converts a Pandas object to a NumPy array. For plain NumPy arrays use .tolist() or simply pass the array directly to functions that accept ndarrays.

Build docs developers (and LLMs) love