Adult Census (1996): Income prediction; standard for fairness.
California Housing: Continuous median property values ().
Vision
MNIST (1998): handwritten digits; the "Hello World" of ML.
CIFAR-10 / 100 (2009): natural colour images.
ImageNet (2009): 1.4M+ images, 1k classes; sparked modern Deep Learning.
Text & Audio
IMDb (2011): 50k movie reviews for sentiment classification.
SQuAD (2016): Reading comprehension QA from Wikipedia.
LibriSpeech (2015): 1,000 hrs of read English speech for ASR.
Structured vs Unstructured
There is often a distinction made between structured and unstructured data. It mainly boils down to whether it is tabular or not.
Examples of structured data are:
patient records
credit card transactions
house prices
Examples of unstructured data are:
images
videos
text
audio
Notice the category where generative AI has worked really well?
Data Processing: Scaling
If we have features with very different scales, the gradient will be much larger for features with larger scales. The training goes BOOM.
For example: patient age (e.g. 0-100) vs creatinine level (e.g. 0.5-2.5).
Solution: Scale the features so that they are in a similar, and often standard, range.
This applies to neural networks too since if you remember we started of with a artificial neuron (Perceptron) and ended up here.
Scaling cont.
Gradient descent and distance metrics (-NN, Ridge, Lasso) are sensitive to feature scales:
1. Standardisation (Z-score Normalisation)
Good for bell-shaped, Gaussian-like distributions.
2. Min-Max Normalisation (Bounded Rescaling)
Bounds features to ; highly vulnerable to extreme outliers.
For examples, image pixels are usually scaled to or .
Data Processing: Missing Values
Deletion
Have too much data? Get rid of the rows/columns with missing values.
Imputation
definition: to calculate something when you do not have exact information, by comparing it to something similar
Mean / Median: replace missing values with the mean / median of the feature.
k-NN: replace missing values with the mean / median of the k-nearest neighbours.
Constant: replace missing values with a constant value.
Binary Indicator: add an explicit binary indicator: .
This business does not come up as much in Deep Learning as it does in tabular ML.
Categorical Encodings
Categorical variables (e.g., Hospital Department: Cardiology, Oncology, Neurology) must be mapped to numbers:
One-Hot Encoding: Maps categories to binary indicator columns:
The Sacred Tri-Partition
Never evaluate a model on the data used to train or tune it:
Training Set (~70%)
Purpose: Learning the model parameters.
Training error is a measure of optimisation capacity, never of generalisation.
Validation Set (~15%)
Purpose: Hyperparameter tuning and model selection.
Also used for debugging the question "my model is not learning anything".
Test Set (~15%)
Purpose: Unbiased estimation of true generalisation.
Touch ONCE at project completion.
If you tune models based on test results, the test set becomes a validation set!
-Fold Cross-Validation
When datasets are moderate in size, a single train/validation split yields high evaluation variance we can't trust the single result.
The -Fold Process
Partition dataset into equal-sized, mutually exclusive subsets (folds)
For each iteration :
Validation Fold:
Training Set:
Fit pipeline on training folds, record metric on .
Compute the mean performance and standard error across folds:
-Fold Cross-Validation
Key Advantages
Every data point serves as a validation sample exactly once.
Mitigates lucky or unlucky validation splits.
Standard choices: or .
Trade-off: times the computational training cost.
With large deep learning era datasets, -fold cross validation is often too computationally expensive. In these cases, a single train/val split is often still used but the datasets are very large (millions of samples) and we assume we have enough samples for the test set to be representative of the distribution.
Stratified -Fold
The Problem
In our hospital readmission dataset, only 5% of patients are readmitted ().
With standard random partitioning:
Small validation folds may contain zero or very few positive cases!
Evaluation metrics fluctuate wildly or collapse mathematically.
The Solution
Stratified -Fold tries to preserve the class ratio in every single fold.
Rule of Thumb: In classification, always use Stratified -Fold unless explicit groups or time series require otherwise.
Stratified -Fold
from sklearn.model_selection import StratifiedKFold, cross_val_score
# Stratified K-Fold automatically maintains 5% positive rate across all 5 folds
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
cv_scores = cross_val_score(full_pipeline, X, y, cv=skf, scoring="...")
print(f"Stratified CV: {cv_scores.mean():.3f} +/- {cv_scores.std():.3f}")
Group -Fold
What happens when individual entities appear multiple times in the dataset?
The Scenario
Patient #42 visits the hospital 4 times across the calendar year.
If we perform standard random splitting:
3 visits land in the Training set.
1 visit lands in the Validation set.
The Catastrophic Failure
The model memorises Patient #42's unique traits (blood type, genetics, rare chronic conditions).
Validation score: 97% accuracy!
Deployed on brand new patients: Performance collapses to 62%!
Group -Fold
Splits are assigned at the group level (by patient_id).
All records belonging to a patient are strictly assigned to either Train or Validation.
from sklearn.model_selection import GroupKFold
# Ensure Patient IDs never straddle train and test
gkf = GroupKFold(n_splits=5)
scores = cross_val_score(full_pipeline, X, y,
groups=patient_ids, cv=gkf)
Data ingestion, tabular wrangling, indexing & grouping
Scikit-Learn
Estimator, Pipeline
Classical algorithms, preprocessing, validation, etc.
SciPy
Sparse matrices, statistical tests
Hypothesis testing (scipy.stats), distribution fittings
Matplotlib
Plots, figures
Thankfully LLMs do this job now
PyTorch
Tensor with autograd engines
Deep learning models and training
It was never about writing code manually. I hated, absolutely hated matplotlib.
Step 3. Model
The more exciting part of the journey.
Depends on the task you are solving: supervised, unsupervised, reinforcement learning.
Depends on the data you have. Is it tabular? Images? Text? Audio? Video?
How much data do you have? Not enough = maybe fine-tune, more data = train from scratch.
The Non-ML Baseline
Never train a complex machine learning model until you have established a baseline.
Sanity check: Verifies data loading and pipeline integrity.
Cost-benefit benchmark: If a 3-line threshold heuristic achieves of an LLM's performance, is the operational complexity worth it?
Inexperienced practitioners jump straight to deep networks, LLMs and what not.
Without a baseline, you cannot tell if an score represents breakthrough intelligence or catastrophic underperformance.
A Hierarchy of Baselines
Level
Baseline Type
Hospital Readmission Example
Primary Purpose
0
Random Guess
Flip coin: predict with prob
Absolute lower floor
1
Majority Class
Predict (Never readmitted) for all patients
Exposes class imbalance
2
Simple Domain Heuristic
If and
Tests human expert rules
3
Simple Linear Model
Logistic Regression on standard features
Quantifies linear signal
4
AI / Complex ML Model
Deep Networks...
Justifies compute/latency
Most tasks you would work on would already have an existing model you can compare against. Start from that given baseline.
Establishing Baselines
import numpy as np
from sklearn.dummy import DummyClassifier
from sklearn.linear_model import LogisticRegression
# 1. Majority class baseline: predicts most frequent class (always y=0)
dummy_majority = DummyClassifier(strategy="most_frequent")
dummy_majority.fit(X_train, y_train)
acc_majority = dummy_majority.score(X_test, y_test)
print(f"Majority Baseline Accuracy: {acc_majority:.3f}") # Often 95%+ !# 2. Simple human domain rule: Age > 75 and Prior Admissions >= 2
y_pred_heuristic = ((X_test["age"] > 75) & (X_test["prior_admissions"] >= 2)).astype(int)
# 3. Simple parametric linear baseline (Logistic Regression)
simple_linear = LogisticRegression(max_iter=1000)
simple_linear.fit(X_train, y_train)
acc_linear = simple_linear.score(X_test, y_test)
print(f"Linear Baseline Accuracy: {acc_linear:.3f}")
My AI Master 9000 model
The future of AI hospital management...
A mission-critical, paradigm-shifting, state-of-the-art multimodal large foundation model (LFM) featuring an agentic, zero-shot, transformer-based mixture-of-experts (MoE) architecture, seamlessly augmented via cross-embodiment, self-supervised spatial-temporal vision-language-action (VLA) robot pre-training, diffusion-policy synthesis, and closed-loop sim-to-real reinforcement learning with human-in-the-loop AI feedback (RLAIF) to enable hyper-scalable, sovereign, edge-native, general-purpose physical intelligence and holistic neuro-symbolic reasoning across dynamic enterprise ecosystems.
You may have detected by now a cynical view, you are not mistaken.
Step 4. Training
Start small, test on a small subset to rule out errors and check if your baselines are working. This is probably my most important advice.
Research engineering is the art of getting things to work, and prompting debugging is a large part of it.
Can you estimate training times?
How is the loss doing? Is it going down?
Is the model improving? We'll look into that after training.
Empirical Risk vs. True Risk
The Generalisation Problem
Let data samples be drawn from an unknown joint probability distribution .
True Generalisation Risk (Expected Loss):
Empirical Risk (Observed Training Loss on Sample of size ):
where i.i.d. samples from .
The Optimisation Paradox
We optimise empirical risk:
But we care only about true risk: .
The Generalisation Gap
Overfitting occurs when while true risk explodes!
The common solution is to get more and moar data like we already discussed in the statistical foundations lectures.
A great example of this is the self-driving car dream. How much driving data do you need until you think it can handle every possible condition out there?
Taxi from driverless firm veers into crime scene, BBC News, Winnie Agbonlahor, Published: 24 April 2026.
Step 5. Evaluation
Did we do anything useful?
How do we know if intelligence is round the corner?
Evaluation is a very important but difficult to define in full. We will look at some common metrics to help start the process.
The Accuracy Paradox
The 95% Illusion
In our hospital dataset of patients where 5% are readmitted:
A dummy model that ignores patient features and always outputs :
It has zero diagnostic value and catches zero at-risk patients!
Goodhart's Law:"When a measure becomes a target, it ceases to be a good measure."
The Confusion Matrix
Multiclass Confusion Matrix
Precision: The Alarm Sounder's Metric
Intuition
"When the model sounds the alarm and flags a patient, how often is it actually right?"
High Precision is critical when:
The intervention is expensive (e.g., performing an exploratory invasive biopsy, shutting down a power grid).
The Cost of Low Precision
"Alarm fatigue"
If 95% of model alerts are false alarms, ignore or disable the predictive system entirely.
Recall (Sensitivity): The Safety Net Metric
Intuition
"Of all patients who were genuinely at risk of readmission, what fraction did the model successfully catch?"
High Recall is critical when:
The consequence of missing a positive case is catastrophic (e.g., fatal cardiac arrest, fraudulent cyberattack).
The Cost of Low Recall
At-risk patients are sent home without follow-up care, leading to severe health complications and preventable emergency readmissions.
Harmonic Mean: The Score
Why can't we simply take the arithmetic mean to balance Precision and Recall?
Arithmetic Mean
Consider a useless model with:
Arithmetic mean:
Hides the true behaviour of the model.
The Score
Harmonic mean:
The harmonic mean approaches zero if either metric collapses.
Moving the Decision Threshold
Classification models (like Logistic Regression) output a continuous probability :
The Myth of
The default software threshold is completely arbitrary. You can play with it to tune your model's performance based on your needs.
Lowering (e.g., ):
Flags more patients Recall , Precision .
Raising (e.g., ):
Flags only confident patients Precision , Recall .
The ROC Curve & AUROC
The Receiver Operating Characteristic (ROC) curve evaluates ranking quality across all possible thresholds:
ROC Mechanics
Sweeps threshold continuously from .
Plots:
Y-axis: True Positive Rate (Recall)
X-axis: False Positive Rate
Diagonal: Random guessing ().
Probabilistic Interpretation of AUROC
The probability that a randomly chosen positive patient receives a higher predicted risk score than a randomly chosen negative patient.
Ranking Perspective
Pairwise ordering: AUROC measures how well the model ranks samples, not whether output values are calibrated probabilities.
(Random): Equivalent to a fair coin toss; positive and negative distributions overlap entirely.
(Perfect): Every positive is ranked strictly above every negative.
The formal derivation is out of scope for us and ventures further into order statistics and probability theory.
ROC vs. PR Curves Under Extreme Imbalance
When the negative class is massive (), false alarms do not impact the FPR denominator: . The ROC curve stays high.
The P-R Curve exposes the collapse: to reach 80% recall, Precision plunges to 25%.
Regression Metrics: When
When predicting continuous targets (e.g., patient Length of Stay in hospital days):
Metric
Formula
Penalty Profile
Dimensionality
Mean Squared Error (MSE)
Quadratic: heavily punishes large errors
(non-intuitive)
Root Mean Squared Error (RMSE)
Quadratic penalty, but on original scale
(interpretable)
Mean Absolute Error (MAE)
Linear: robust to extreme outliers
(median-like)
Selection Rule: Use RMSE when large errors are disproportionately disastrous; use MAE when data contains anomalous measurement spikes.
Evaluation Studio
Qualitative Evaluation
Never settle for scalar summary metrics! Inspect individual failure samples. Try to understand what is the model good at, what is it bad at.
Clever Hans
In 1904, a German horse named Clever Hans was famous for performing arithmetic.
Investigation revealed Hans could not do math: he was detecting subtle, involuntary head micro-tensions from the questioner.
Clever Hans (1904), CC BY-SA 4.0 WikiMedia Commons
Before tuning a model, distinguish between internal weights and structural controls:
Model Parameters ()
Learned automatically from the Training Set via numerical optimisation:
Examples:
Weights in neural network ()
Bias terms ()
Decision tree split thresholds
Hyperparameters ()
Structural configuration dials that govern model capacity and regularisation.
Cannot be learned by minimising training loss!
Examples:
Regularisation weight
Number of neighbours in -NN
Maximum tree depth
Learning rate in gradient descent
Grid Search vs. Random Search
How should we explore multi-dimensional hyperparameter spaces?
Nested Cross-Validation
What if you tune hyperparameters on cross-validation folds and report the best CV score as your result?
If you have large amounts of data, tune on the validation set.
If you have moderate sized datasets, use nested cross-validation.
The Nested CV Solution
Outer Loop (e.g., 5-Fold): Evaluates overall generalisation performance of the modelling process.
Inner Loop (e.g., 3-Fold): Conducts hyperparameter tuning strictly within each outer training slice.
Guarantees that reported performance has never been observed during hyperparameter selection.
Code: Hyperparameter Tuning
from sklearn.model_selection import RandomizedSearchCV, StratifiedKFold
# Define hyperparameter search distributions
param_distributions = {
"classifier__C": [1e-4, 1e-3, 1e-2, 1e-1, 1, 1e1, 1e2],
"classifier__penalty": ["l1", "l2"],
"classifier__solver": ["liblinear"]
}
# Wrap pipeline inside RandomizedSearchCV
search = RandomizedSearchCV(
estimator=full_pipeline,
param_distributions=param_distributions,
n_iter=50, # 50 random parameter samples
scoring="roc_auc",
cv=StratifiedKFold(n_splits=5, shuffle=True),
random_state=42,
n_jobs=-1
)
# Fit search: all preprocessors inside pipeline are refitted per fold!
search.fit(X_train, y_train)
print(f"Optimal Hyperparameters: {search.best_params_}")
print(f"Best Inner CV ROC-AUC: {search.best_score_:.3f}")
# Evaluate tuned pipeline on untouched, vaulted test set
final_test_auc = search.score(X_test, y_test)
print(f"Vaulted Test Set ROC-AUC: {final_test_auc:.3f}")
Trust me bro benchmarks
The Scenario
Model A (GPT-41): Test Accuracy =
Model B (GPT-42): Test Accuracy =
The Question
Did Model B uncover genuine intelligence, or did it just win the random seed lottery on this specific test partition?
In AI and ML, we mostly nowadays highlight the best result we can find on a benchmark in bold and move on.
OpenAI's performance charts in the GPT-5 launch video are such a mess you have to think GPT-5 itself probably made them, and the company's attempted fixes raise even more questions.
PC Gamer, Jeremy Laird, August 12, 2025
Confidence Interval
The test set consists of i.i.d. pairs . For each sample, the model prediction is . So far so good.
Let's define:
Here, , where is the unknown true population accuracy. We cannot access , but we can estimate it using the test set.
2. Sample Mean & Central Limit Theorem
Test accuracy is the sample mean , so and .
By the Central Limit Theorem, the standardised error converges to a standard normal:
So we got a normal distribution for our test accuracy:
But we don't know ...
Sometimes it's okay not to know something, you can stop and enjoy other things or...
3. Plug-in Estimator
Plugging in for in the standard error (Slutsky's theorem) which guarantees that as we still converge to . So we can write:
What is the standard error? It is the standard deviation of your estimate if you were to repeat the experiment many times.
While standard deviation () measures the variability of individual data points, standard error () measures the variability of a summary statistic (like test accuracy ).
Wald (Confidence) Interval
After plugging in and solving for true :
The Wald Confidence Interval (Normal approximation) at level :
For a 95% confidence interval ():
Limitations of the Wald Interval
Can produce bounds outside when or , or when is small. If , estimated variance collapses to 0. It also does not generalise to non-linear metrics like or AUROC.
Empirical Confidence Intervals
How do we quantify estimation uncertainty on our test metrics without making assumptions?
The Bootstrap Protocol
Given test set :
For (e.g., iterations):
Sample records with replacement from .
Compute metric (e.g., or AUROC).
Compute the Confidence Interval directly from empirical quantiles:
Bootstrap intervals make zero assumptions about normality and accurately reflect test set sample variance.
Bootstrap Confidence Intervals in Python
Compute non-parametric confidence intervals for paired evaluation metrics:
import numpy as np
from scipy.stats import bootstrap
from sklearn.metrics import f1_score
# Paired test labels and model predictions
data = (y_true, y_pred)
# Compute empirical 95% bootstrap confidence interval
res = bootstrap(
data,
statistic=...,
paired=True, # Resample paired (y_true_i, y_pred_i) together
n_resamples=2000,
confidence_level=0.95,
method='percentile',
random_state=42
)
print(f"95% CI: [{res.confidence_interval.low:.3f}, {res.confidence_interval.high:.3f}]")
McNemar’s Test for Paired Classifiers
McNemar’s Test for Paired Classifiers
where (B wins) and (A wins) are discordant error counts:
Evaluate both models on the identical test set to form the paired contingency table.
Under , the statistic follows a distribution with 1 df.
If (), we reject the null hypothesis: Model B's edge is statistically significant!
Just follow along for now.
Example
Setup: Comparing ResNet-50 () vs. Transformer () on test images.
-value: the probability of observing a discordant split at least this extreme if both models were equally accurate ().
Conclusion: Reject . The accuracy advantage of is statistically significant.
from scipy.stats import binomtest, chi2
b, c = 80, 120
p_chi2 = chi2.sf((abs(b - c) - 1)**2 / (b + c), df=1) # p = 0.0058
p_exact = binomtest(b, n=b + c, p=0.5).pvalue # p = 0.0057
What the heck?
Okay, okay, okay. I see the pain, I feel the pain, I am the pain.
Step 1: FOCUS on the Disagreements
Ignore the images where both models agree ( and ).
Look only at the images where one model is right.
Step 2: Null Hypothesis () = Fair Coin Flips
If and are equally good, each disagreement is a 50/50 coin toss ().
Let be the number of times wins out of disagreements:
Expected wins and variance under :
What the heck?
Step 3: Normal Approximation (-Score)
Central Limit Theorem (CLT) standardise using :
Step 4: Square
The square of a standard normal variable is a variable ():
Step 5: Add Continuity Correction
Why the ? Because and are discrete integers, shifting 1 sample from to changes by . Subtracting (Edwards' continuity correction) adjusts for the half-step on the continuous curve: