Course topics

By WebNest Studio

Python Tutorial

NumPy for Maths, Statistics and Linear Algebra

NumPy is also a complete numerical toolkit. This lesson covers the random number generator for simulations and sampling, descriptive statistics and correlation, sorting and searching, linear algebra (matrix multiplication, solving systems of equations, inverses), handling missing values with NaN, and saving and loading arrays — the maths you will meet again in machine learning.

Random Numbers and Simulation

Create a generator with rng = np.random.default_rng(seed). Use integers, random (uniform 0–1), normal, choice (with replace and p for weights), shuffle and permutation. A fixed seed makes results reproducible — essential for experiments and machine learning. Simulations (Monte Carlo) estimate probabilities by generating many random trials at once with vectorised code.

Linear Algebra

A @ B (or np.dot) is matrix multiplication, while A * B multiplies element-wise. np.linalg provides solve (solve Ax = b), inv, det, norm, eig and lstsq (least squares, the maths behind linear regression). Prefer solve to multiplying by an inverse: it is faster and more accurate.

NaN, Sorting and Saving

Missing numeric values are represented by np.nan; any arithmetic with NaN gives NaN, so use np.nanmean, np.nansum and np.isnan. np.sort returns a sorted copy, argsort returns the order of indices (useful for ranking), and np.searchsorted finds insertion points. Save arrays with np.save/np.load (binary .npy) or np.savetxt/np.loadtxt for text.

Examples

Random sampling and a Monte Carlo simulation

Python
import numpy as np

rng = np.random.default_rng(seed=2026)
print(rng.choice(["heads", "tails"], size=6))
print(rng.choice(["red", "green", "blue"], size=5, p=[0.6, 0.3, 0.1]))
deck = np.arange(1, 11)
rng.shuffle(deck)
print(deck)

# Probability that two dice sum to 7 (exact answer: 1/6 = 0.1667)
rolls = rng.integers(1, 7, size=(1_000_000, 2))
print(round(np.mean(rolls.sum(axis=1) == 7), 3))

heights = rng.normal(loc=165, scale=8, size=10_000)
print(round(heights.mean(), 1), round(heights.std(), 1))
print("share taller than 180 cm:", round(np.mean(heights > 180), 3))
Output
['tails' 'heads' 'heads' 'tails' 'heads' 'heads']
['red' 'red' 'green' 'blue' 'red']
[ 6  9  4  1  5  8 10  2  7  3]
0.166
164.9 8.0
share taller than 180 cm: 0.03

Statistics, correlation, NaN handling and ranking

Python
import numpy as np

hours = np.array([1, 2, 3, 4, 5, 6, 7, 8])
marks = np.array([35, 45, 50, 58, 65, 72, 80, 88])
print("mean:", marks.mean(), "median:", np.median(marks), "var:", marks.var().round(1))
print("correlation:", np.corrcoef(hours, marks)[0, 1].round(3))
slope, intercept = np.polyfit(hours, marks, deg=1)       # best straight line
print(f"marks = {slope:.2f} * hours + {intercept:.2f}")

readings = np.array([21.5, np.nan, 23.0, 22.1, np.nan])
print(readings.mean(), np.nanmean(readings).round(2), np.isnan(readings).sum(), "missing")

scores = np.array([72, 95, 64, 88])
order = np.argsort(scores)[::-1]                          # indices, highest first
print(np.sort(scores), order, scores[order])
print(np.searchsorted([100, 200, 500, 1000], 350))        # which price band
Output
mean: 61.625 median: 61.5 var: 285.7
correlation: 0.999
marks = 7.37 * hours + 28.46
nan 22.2 2 missing
[64 72 88 95] [1 3 0 2] [95 88 72 64]
2

Matrix multiplication and solving equations

Python
import numpy as np

A = np.array([[2, 1],
              [1, 3]])
B = np.array([[1, 0],
              [4, 2]])
print(A * B)                   # element-wise
print(A @ B)                   # matrix product
print(np.linalg.det(A).round(2), np.linalg.inv(A).round(2).tolist())

# 3 pens + 2 notebooks = 160 ; 1 pen + 4 notebooks = 220 -> prices?
coefficients = np.array([[3, 2],
                         [1, 4]])
totals = np.array([160, 220])
pen, notebook = np.linalg.solve(coefficients, totals)
print(f"pen = {pen:.0f}, notebook = {notebook:.0f}")

np.save("prices.npy", np.array([pen, notebook]))
print(np.load("prices.npy"))
print(np.linalg.norm([3, 4]))  # length of a vector
Output
[[2 0]
 [4 6]]
[[ 6  2]
 [13  6]]
5.0 [[0.6, -0.2], [-0.2, 0.4]]
pen = 20, notebook = 50
[20. 50.]
5.0

Common Mistakes

  • Using * when you mean matrix multiplication (@).
  • Computing inv(A) @ b instead of np.linalg.solve(A, b).
  • Letting a single NaN turn every result into NaN — use nan-aware functions or clean the data.
  • Forgetting to set a seed, making experiments impossible to reproduce.
  • Comparing floats with == instead of np.isclose().

Key Points to Remember

  • default_rng(seed) gives reproducible random numbers for sampling and simulation.
  • mean, median, var, std, percentile, corrcoef and polyfit describe data.
  • @ multiplies matrices; np.linalg solves systems, inverts and decomposes them.
  • Handle NaN with isnan and nan-functions; sort with sort/argsort.
  • Save arrays with np.save/np.load.

Practice the examples

Change an input, predict the result, then compare it with the output. Explain why the result changes.

Use your local project environment for these examples. Codelab currently runs Python and HTML/CSS/JavaScript; framework examples may need project dependencies.