Chapter 7 — Numerical Computing with NumPy
NumPy is the foundation of scientific Python. Its n-dimensional array (ndarray) and vectorized operations make numerical work fast and concise. Nearly every data-science library builds on NumPy, so mastering it pays off everywhere.
Learning Objectives
- Create arrays from lists and built-in functions.
- Inspect shape, dtype, and size.
- Index and slice arrays, including boolean masks.
- Perform vectorized arithmetic and use broadcasting.
- Compute aggregations along axes.
- Generate random numbers with
np.random. - Apply basic linear-algebra operations.
Prerequisites / Imports
import numpy as np
1 Creating Arrays
Make arrays from lists or with arange, linspace, zeros, ones, eye.
a = np.array([1, 2, 3, 4])
print('1-D:', a, 'dtype:', a.dtype)
b = np.array([[1, 2, 3], [4, 5, 6]])
print('2-D shape:', b.shape)
b
1-D: [1 2 3 4] dtype: int32 2-D shape: (2, 3)
array([[1, 2, 3],
[4, 5, 6]])print('arange:', np.arange(0, 10, 2))
print('linspace:', np.linspace(0, 1, 5))
print('zeros 2x3:'); print(np.zeros((2, 3)))
print('eye 3:'); print(np.eye(3))
arange: [0 2 4 6 8] linspace: [0. 0.25 0.5 0.75 1. ] zeros 2x3: [[0. 0. 0.] [0. 0. 0.]] eye 3: [[1. 0. 0.] [0. 1. 0.] [0. 0. 1.]]
2 Array Attributes
shape, ndim, size, dtype describe an array.
x = np.random.default_rng(0).random((3, 4))
print('shape:', x.shape, 'ndim:', x.ndim, 'size:', x.size)
print('dtype:', x.dtype)
shape: (3, 4) ndim: 2 size: 12 dtype: float64
3 Indexing and Slicing
Use [row, col]; slices return views.
m = np.arange(12).reshape(3, 4)
print(m)
print('row 1:', m[1])
print('col 2:', m[:, 2])
print('sub-block:', m[0:2, 1:3])
[[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11]] row 1: [4 5 6 7] col 2: [ 2 6 10] sub-block: [[1 2] [5 6]]
4 Boolean Indexing (Masking)
Filter arrays with a Boolean mask — a key data-cleaning technique.
data = np.array([5, 12, 3, 18, 7, 25, 2])
mask = data > 10
print('mask:', mask)
print('values > 10:', data[mask])
mask: [False True False True False True False] values > 10: [12 18 25]
5 Vectorized Operations
Arithmetic applies elementwise without Python loops — fast and clean.
v = np.array([1, 2, 3, 4])
print('v + 10:', v + 10)
print('v * 2:', v * 2)
print('v ** 2:', v ** 2)
print('v * v:', v * v)
v + 10: [11 12 13 14] v * 2: [2 4 6 8] v ** 2: [ 1 4 9 16] v * v: [ 1 4 9 16]
6 Broadcasting
NumPy expands smaller arrays to match shapes, enabling concise math.
row = np.array([1, 2, 3]) # shape (3,)
col = np.array([[10], [20], [30]]) # shape (3,1)
print('broadcast sum:')
print(col + row)
broadcast sum: [[11 12 13] [21 22 23] [31 32 33]]
7 Aggregations
sum, mean, std, min, max accept an axis argument.
m = np.arange(12).reshape(3, 4).astype(float)
print('total mean:', m.mean())
print('column means:', m.mean(axis=0))
print('row sums:', m.sum(axis=1))
print('min/max:', m.min(), m.max())
total mean: 5.5 column means: [4. 5. 6. 7.] row sums: [ 6. 22. 38.] min/max: 0.0 11.0
8 Random Numbers
Use np.random.default_rng(seed) for reproducible randomness — vital for simulations and ML.
rng = np.random.default_rng(42)
print('5 uniform [0,1):', rng.random(5))
print('3 integers 1..100:', rng.integers(1, 101, size=3))
print('normal samples:', rng.normal(loc=0, scale=1, size=4))
5 uniform [0,1): [0.77395605 0.43887844 0.85859792 0.69736803 0.09417735] 3 integers 1..100: [53 98 74] normal samples: [-0.31624259 -0.01680116 -0.85304393 0.87939797]
9 Linear Algebra Basics
np.dot / @ for matrix multiplication; np.linalg for solve and inverse.
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print('A @ B:'); print(A @ B)
print('transpose A:'); print(A.T)
print('det:', np.linalg.det(A))
print('solve Ax = [1,2]:', np.linalg.solve(A, [1, 2]))
A @ B: [[19 22] [43 50]] transpose A: [[1 3] [2 4]] det: -2.0000000000000004 solve Ax = [1,2]: [0. 0.5]
Case Study: Standardizing Test Scores
Standardize a synthetic set of exam scores to z-scores ($(x - \mu)/\sigma$) using vectorized NumPy — a routine preprocessing step.
rng = np.random.default_rng(7)
scores = rng.normal(loc=75, scale=12, size=50).round(1)
mu, sigma = scores.mean(), scores.std()
z = (scores - mu) / sigma
print(f'mean={mu:.2f} std={sigma:.2f}')
print('first 5 z-scores:', np.round(z[:5], 2))
print('mean of z (should be ~0):', z.mean().round(10))
print('std of z (should be ~1):', z.std().round(10))
mean=71.49 std=10.62 first 5 z-scores: [ 0.33 0.67 0.02 -0.68 -0.19] mean of z (should be ~0): -0.0 std of z (should be ~1): 1.0
Exercises
- Create a 4x4 array of integers from 0 to 15 and reshape it.
- Select the second row and third column of a 3x3 array.
- Use a Boolean mask to extract all even numbers from an array.
- Add a 1-D array of shape (3,) to a 2-D array of shape (4, 3) using broadcasting.
- Compute the column-wise means of a 5x3 random array.
- Generate 1000 normal samples and count how many are more than 1 standard deviation from the mean.
- Multiply two 2x2 matrices with
@and verify againstnp.dot. - Standardize a synthetic dataset and confirm the result has mean 0 and std 1.
- Explain the difference between a view and a copy of a slice.
- Use
np.linspaceto create 50 points from 0 to 2π and compute their sines.
Python Data Science: From Foundations to Applications — Chapter 7