Search Tech Journey

Find topics, journeys and posts

6-month learning plan84 / 130
back to blog
mlintermediate 55m read

S084 · The ML Mental Model — Features, Labels, Train/Val/Test

The one mental model that unlocks all of classical ML — data becomes X and y, splits prevent lying to yourself, and a loss function turns a guess into gradient descent.

🤖Machine LearningM11 · Classical ML· Session 084 of 130 90 min

🎯 Internalise the X/y/split/loss/metric pipeline so every future ML session slots into a mental scaffold you already own.

Why this session exists

Every ML paper, blog post, tutorial, and library assumes you have one specific mental model: data is a matrix X and a vector y, you split into train/val/test, you fit a model that minimises a loss on train, and you report a metric on test. Once that scaffold exists in your head, everything else — decision trees, gradient boosting, neural nets, transformers — is a variation on it. Without it, you'll cargo-cult .fit() calls forever. This session drills the scaffold.

You will be able to
  • Describe any dataset as an (n × d) feature matrix X and a length-n label vector y.
  • Explain the difference between train / val / test and why every one of them exists.
  • Distinguish loss (what the model minimises) from metric (what humans grade).
  • Recognise the top 5 data leakage patterns before they cost you a job interview.
  • Draw the ML lifecycle diagram and name what happens at each step.

Prerequisites

  • S005 · Python variables and types — comfortable with numpy arrays.
  • S040 · Probability basics — comfortable with mean/variance/distribution.
  • S033 · Pandas fundamentals — you can load a CSV into a DataFrame.


(a) Intuition · 5 min

ML is fancy curve-fitting with rules against cheating
🌍 Real world

Imagine you're a teacher grading students. You give them 100 practice problems (train), then 20 unseen problems that look similar (val) to check if they're really learning versus memorising. Finally, at the end of term, a completely separate 50-problem final exam (test) that no student has seen and no teacher has peeked at.

Now imagine one student secretly gets a look at the final exam beforehand. Their score is meaningless — they didn't learn anything, they just memorised the answers. That's data leakage. The whole ceremony of splits exists to prevent that one thing.

💻 Code world

An ML model is a function ŷ = f(X; θ). You have data (X, y). You pick a model family (linear, tree, neural net), then you find the parameters θ that minimise some loss L(y, ŷ) on the training data.

The problem: any expressive-enough model can memorise the training set and score 100 %. So we hide part of the data (test), tune on a middle chunk (val), and only look at the test score at the very end. If those numbers agree, the model actually learned something.

The five nouns to own before you touch a model

ML vocabulary you must own
  • Feature (X_j) — a column. One measurable property per example. n examples × d features = X matrix.
  • Label (y) — what you're predicting. A number (regression) or category (classification).
  • Model — the family of functions f, plus the parameters θ you're going to learn.
  • Loss (L) — a differentiable, per-example scoring function that says ‘worse = bigger number.’ The model minimises this.
  • Metric — a human-readable score (accuracy, AUC, RMSE) computed on val/test. Doesn't have to be differentiable.

How ML actually got to now

  1. 1957
    Perceptron · Rosenblatt
    First learning algorithm — a linear classifier trained by mistake correction. Predicted image classification would be solved in ‘a few years.’
  2. 1986
    Backpropagation popularised
    Rumelhart, Hinton, Williams show how to train multi-layer nets. Sits idle for 20 years — too little data, too little compute.
  3. 2001
    Random Forest · Breiman
    Bagging + random feature sampling. Rules Kaggle for a decade before deep learning arrives.
  4. 2007
    scikit-learn v0.1
    Cournapeau's Google Summer of Code project becomes the default ML library on Earth.
  5. 2012
    AlexNet on ImageNet
    Deep learning + GPUs shatter the previous SOTA by 10 points. The modern ML era begins.
  6. 2016
    XGBoost dominates Kaggle
    For tabular data, gradient boosting beats deep learning on almost every problem — still true in 2025.
  7. 2022
    ChatGPT
    Consumer inflection point for LLMs. Classical ML doesn't die; it becomes the boring, load-bearing 80 % of every real system.

(b) Visual walkthrough · 15 min

The ML lifecycle in one picture

The X, y matrix — every dataset, always

How to think about any dataset

Rows (n examples)
One row = one thing you want to predict about. A customer, a house, a click. n = number of examples.
examples
Columns (d features)
Each column is one measurable input. Numerical (price), categorical (color), text (review), image (pixels flattened). d = feature dimensionality.
features
Target vector y (length n)
The thing to predict. If regression: y ∈ ℝⁿ. If classification: y ∈ {0,1,...,K-1}ⁿ.
labels
The mapping f: X → ŷ
The model is a function from a d-dim row to a prediction. Linear = weighted sum. Tree = a series of if-else splits. NN = a stack of matmul + nonlinearity.
model
Parameters θ
The numbers inside f that get learned. Linear: d weights + 1 bias. Tree: the split thresholds. NN: millions to billions of weights.
params

Splits — the three-way divide

Train set (60–80 %)

Where the model sees the data

  • The only data the fit process ever sees.
  • Determines the parameters θ directly.
  • Bigger = better fit, but at some point returns diminish.
  • Data augmentation is applied here.
  • You look at this all you want.
Val set (10–20 %)

Where you choose the model

  • Used to pick hyperparameters (learning rate, tree depth, k).
  • Used for early stopping.
  • You look at this many times — that's fine, it's what it's for.
  • In cross-validation, val is rotated through k folds of train.
  • Val score guides your decisions; test score judges them.
Test set (10–20 %)

Where reality bites

  • Touched exactly ONCE, at the very end.
  • Reports the honest generalisation number.
  • If val ≈ test, you're good. If val >> test, you've overfit to val.
  • In competitions this is the private leaderboard.
  • In production, this is the past 30 days you didn't train on.

Loss vs metric — a concrete table

Regression

y is continuous

  • Loss: MSE = mean((y - ŷ)²) — smooth, differentiable, penalises big errors.
  • Loss: MAE = mean(|y - ŷ|) — robust to outliers, less smooth.
  • Metric: RMSE = √MSE (same units as y, easy to report).
  • Metric: MAPE = mean(|y-ŷ|/|y|) — percentage error, easy to explain to PMs.
  • Metric: R² — proportion of variance explained.
Binary classification

y ∈ {0, 1}

  • Loss: binary cross-entropy = -Σ[y log ŷ + (1-y) log(1-ŷ)].
  • Metric: accuracy — % correct. Useless on imbalanced data.
  • Metric: precision, recall, F1 — the imbalanced-safe trio.
  • Metric: ROC-AUC — threshold-independent ranking quality.
  • Metric: PR-AUC — better for very imbalanced problems (fraud, spam).

Common misconception
✗ What most people think

"Machine learning is a better kind of programming — instead of writing rules by hand, the model learns the rules. So anything I could eventually code, I could get a model to learn, just faster and with less effort."

✓ What is actually true

ML does not learn rules; it fits a function that minimises a loss on a sample of data drawn from some distribution. It buys you the ability to approximate a function you cannot specify — but it costs you determinism, explainability, and any guarantee outside the training distribution. If you can write the rule, writing it is almost always better: it is testable, debuggable, and it does not silently degrade when the world shifts.

Why the myth is so sticky

The myth is sticky because it is genuinely true in the narrow band where ML earns its keep — perception, language, ranking, and anywhere the rule is real but inexpressible. Nobody can write down the rule for "is this a cat", so learning it feels like magic that must generalise to everything. But the moment the task is expressible ("flag transactions over ₹50,000 from new accounts"), the learned version is strictly worse: it will be right 98% of the time instead of 100%, and you will not be able to say why it was wrong the other 2%.

Prove it to yourself

The cheapest ML decision test in existence — run it before any model work:

1. Can a domain expert state the rule in one sentence?
     yes -> write the rule. You are done.

2. Can they do the task correctly in under ~1 second,
   but NOT explain how?
     yes -> supervised learning is a good fit.

3. Do you have labelled examples of past decisions
   and their outcomes?
     no  -> you have a data-collection project, not an ML project.

4. Is a probabilistic answer acceptable to the business?
     no  -> ML is the wrong tool regardless of accuracy.

Most failed ML projects fail at step 3, and almost none of them noticed before staffing a team.

From first principles
Start with the question

Why must you hold out a test set at all? You have a fixed dataset and you want the best model on it — deliberately throwing away 20% of your data seems like it can only make the model worse. It does. Do it anyway.

  1. 1
    The thing you actually care about is performance on future data you have never seen — the generalisation error. Training error is only a proxy for it.
    forced by · a model that memorises the training set has zero training error and no value
  2. 2
    Training explicitly minimises error on the training set. So training error is a biased estimate of generalisation error, and biased in the optimistic direction by construction.
    forced by · you optimised the very quantity you are now using as a measurement
  3. 3
    Any data used to make a choice — which features, which hyperparameters, when to stop, which of five candidate models — becomes contaminated in the same way, even if no gradient ever touched it. Selection is a form of fitting.
    forced by · choosing the best of many options on a dataset fits that dataset's noise, exactly as gradient descent would
  4. 4
    Therefore an unbiased estimate requires data that has influenced no decision whatsoever. That forces a three-way split: train (fits parameters), validation (fits your choices), test (touched once, at the end).
    forced by · each level of optimisation needs its own untouched holdout to be measured honestly
  5. 5
    And if the data has temporal or group structure, the split must respect it. Randomly splitting a time series lets the model learn from the future to predict the past; randomly splitting rows that share a user or device leaks that entity across the boundary.
    forced by · the split must mimic the deployment gap between what you will know and what you must predict
⇒ Therefore

Therefore the test set is not a measurement convenience — it is the only mechanism by which any performance number you report is meaningful. Every time you look at it and change something, you convert it into another validation set.

And note what this predicts: a model can show excellent cross-validated scores and still fail in production, without anyone having cheated, if the split did not reproduce the real deployment gap. That is precisely the shape of leakage bugs — a feature computed with information unavailable at prediction time, or the same customer in both folds. The derivation says the split must mirror deployment; leakage is what it looks like when it doesn't.

Mental modelCurve fitting with a memory of examples

Strip away the vocabulary and every supervised model is the same three objects: a parameterised function f(x; θ) that maps inputs to outputs, a loss that scores how wrong it is on examples you have, and a search procedure that adjusts θ to reduce that loss. Linear regression, gradient boosting, and a 70B transformer differ only in the shape of f and the cleverness of the search.

The model has no concept of causation, meaning, or the world. It has a compressed record of correlations present in the data you showed it. Everything it does right and everything it does catastrophically wrong follows from that one sentence.

  • The model can only learn patterns that exist in the data you gave it. Missing signal cannot be recovered by a better architecture — feature and data quality dominate model choice.
  • Correlation is all it has. It will happily learn a proxy for the label that is unavailable, illegal, or accidental — that is leakage and bias, and both are the same mechanism.
  • Performance is only defined relative to a distribution. When the world shifts, the model does not know; it keeps predicting confidently. Monitoring is not optional.
  • Always establish the dumb baseline first — predict the majority class, the last value, or the group mean. If your model does not beat it clearly, you have an expensive constant.
🔔 Fires when you see

Fire this the moment you see: "let's use AI for this" before anyone has stated the loss or the label · a model with no baseline comparison · an accuracy number on an imbalanced dataset · a feature that is suspiciously predictive · a model in production with no drift monitoring · a business asking why a specific prediction was made.

The tradeoff

You have a problem where a hand-written rule set currently works "well enough". Do you keep the rules, replace them with a model, or run a hybrid?

Hand-written rules
+ you gain fully deterministic and auditable — you can explain any decision to a regulator, a customer, or a court. Unit-testable, versionable, instantly changeable, zero training infrastructure, and it works on day one with no data.
− you pay complexity grows superlinearly with the number of interacting conditions; nobody dares delete an old rule; and it cannot capture patterns humans have not noticed. Maintenance cost eventually exceeds the cost of the model you were avoiding.
pick when the rules are stable, countable (roughly under a few dozen), legally required to be explainable, or you have no labelled outcome data yet
Learned model
+ you gain captures interactions nobody enumerated, adapts by retraining rather than by editing logic, and typically dominates rules once the number of relevant conditions is large or the signal is genuinely high-dimensional
− you pay you inherit an entire discipline: labelling, feature pipelines, training infrastructure, versioning, drift monitoring, and an explainability problem. It is probabilistic, so some fraction of decisions will be confidently wrong with no traceable cause.
pick when you have labelled outcome data at meaningful volume, the pattern is complex or shifting, and probabilistic answers are acceptable to the business
Hybrid — model scores, rules gate
+ you gain the model provides ranking or a risk score while hard rules enforce the non-negotiables (regulatory limits, safety floors, known-bad blocks). You get the model's pattern-finding without letting it violate a constraint that must never be violated.
− you pay two systems to maintain and reason about, and the interaction between them is where the subtle bugs live — a rule can silently mask a model regression, so your offline metrics stop reflecting production behaviour
pick when there exists any decision the business will not tolerate the model getting wrong — which for fraud, safety, compliance, and money movement is essentially always
What a senior engineer actually does

Start with rules and a measured baseline, always. The baseline is not a formality — it is the only way to know later whether the model added value, and a surprising number of shipped models never beat it. Move to ML when rule maintenance becomes the bottleneck or when the rules demonstrably cannot capture the signal, and let that be an observation rather than an assumption.

In production the hybrid is usually where mature systems land, because the real requirement is rarely "maximise accuracy" — it is "maximise accuracy subject to never doing the following things". Rules express hard constraints cleanly; models express soft preferences cleanly. Using either one for the other's job is the actual mistake.


(c) Hands-on · 25 min

We're going to load a real dataset (California housing), split it properly, fit a baseline, and demonstrate two forms of data leakage.

# ml_scaffold.py — the mental model in ~120 lines of runnable code.
import numpy as np
import pandas as pd
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split, KFold, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
from sklearn.dummy import DummyRegressor
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.pipeline import Pipeline
 
np.random.seed(42)
 
# --- 1. Load raw data → (X, y) ---
data = fetch_california_housing(as_frame=True)
X: pd.DataFrame = data.frame.drop(columns=["MedHouseVal"])
y: pd.Series = data.frame["MedHouseVal"]
print(f"Shape: X={X.shape}, y={y.shape}")
print(f"Features: {list(X.columns)}")
print(f"Label stats: min={y.min():.2f}, max={y.max():.2f}, mean={y.mean():.2f}")
 
# --- 2. Split BEFORE any fitting or scaling ---
X_trainval, X_test, y_trainval, y_test = train_test_split(
    X, y, test_size=0.15, random_state=42
)
X_train, X_val, y_train, y_val = train_test_split(
    X_trainval, y_trainval, test_size=0.15, random_state=42
)
print(f"Split → train={len(X_train)}, val={len(X_val)}, test={len(X_test)}")
 
# --- 3. Baseline — always start here ---
baseline = DummyRegressor(strategy="mean")
baseline.fit(X_train, y_train)
rmse_baseline = mean_squared_error(y_val, baseline.predict(X_val), squared=False)
print(f"[baseline · predict mean] val RMSE = {rmse_baseline:.3f}")
 
# --- 4. Real model in a pipeline — scaler fit ONLY on train ---
pipe = Pipeline([
    ("scaler", StandardScaler()),   # fit on train, transform val/test
    ("model", LinearRegression()),
])
pipe.fit(X_train, y_train)
rmse_val = mean_squared_error(y_val, pipe.predict(X_val), squared=False)
r2_val = r2_score(y_val, pipe.predict(X_val))
print(f"[linear · pipeline]     val RMSE = {rmse_val:.3f}, R² = {r2_val:.3f}")
 
# --- 5. Cross-validation on train+val (proper hyperparam search) ---
cv_rmse = -cross_val_score(
    pipe, X_trainval, y_trainval,
    scoring="neg_root_mean_squared_error", cv=KFold(5, shuffle=True, random_state=42)
).mean()
print(f"[linear · 5-fold CV]    mean RMSE = {cv_rmse:.3f}")
 
# --- 6. FINAL test-set evaluation · ONE TIME ONLY ---
rmse_test = mean_squared_error(y_test, pipe.predict(X_test), squared=False)
r2_test = r2_score(y_test, pipe.predict(X_test))
print(f"[linear · TEST · one-shot] RMSE = {rmse_test:.3f}, R² = {r2_test:.3f}")
 
# --- 7. DEMO — data leakage via scaling on the whole set (WRONG) ---
print("\n=== LEAKAGE DEMO — do NOT do this ===")
scaler_wrong = StandardScaler().fit(X)          # fit on ALL data (leak!)
X_wrong = scaler_wrong.transform(X)
X_wtrain, X_wtest, y_wtrain, y_wtest = train_test_split(
    X_wrong, y, test_size=0.15, random_state=42
)
m_wrong = LinearRegression().fit(X_wtrain, y_wtrain)
rmse_wrong = mean_squared_error(y_wtest, m_wrong.predict(X_wtest), squared=False)
print(f"[leaky scaler]  test RMSE = {rmse_wrong:.3f}  (looks similar, but the mean/std saw the test set)")
print("On this small dataset the effect is tiny; on real projects the leaky number can be 20-40% too optimistic.")
 
# --- 8. DEMO — target leakage (WRONG) ---
print("\n=== LEAKAGE DEMO 2 — target leakage ===")
X_leaky = X.copy()
X_leaky["cheat_col"] = y + np.random.normal(0, 0.01, size=len(y))  # near-perfect proxy for target
X_lt, X_lte, y_lt, y_lte = train_test_split(X_leaky, y, test_size=0.15, random_state=42)
m_leak = LinearRegression().fit(X_lt, y_lt)
print(f"[target-leak]   test R² = {r2_score(y_lte, m_leak.predict(X_lte)):.4f}  ← if you see 0.99 in your first model, something is wrong")

What each block does

Anatomy of the scaffold

1 · Load → (X, y)
Every classical ML workflow starts here. If your ‘data loading’ takes 200 lines and produces something that isn't a rectangular X + y, redesign until it is.
load
2 · Split BEFORE anything
Splits happen first. Any statistic (mean, std, vocab, PCA) computed on the whole dataset leaks test info. Fit on train, transform others.
split
3 · Baseline
Always predict the mean (regression) or majority class (classification) as your zero. Any real model must beat it — if not, you have a data problem, not a model problem.
sanity
4 · Pipeline
sklearn Pipeline makes it structurally impossible to leak — scaler.fit() happens inside pipe.fit(X_train) so it never sees val/test.
hygiene
5 · Cross-validation
For small datasets, a single val split is noisy. K-fold rotates through k splits so every example serves as val exactly once. Report mean ± std.
cv
6 · Test — ONCE
The single most important line. Any decision after this line (choose a different model, different features, different scaler) invalidates the number.
final
7 · Leakage: preprocess
Fit scaler on the whole X → the mean/std includes test statistics → your model implicitly ‘knew’ the test distribution. On this dataset, tiny effect; on real projects, disaster.
leak
8 · Leakage: target
A feature that's basically y itself. This happens in real projects when someone joins in ‘the fraud label’ into your feature table by accident.
leak
Try itBreak your own model on purpose to build intuition

Add a loop that trains the same pipeline on progressively smaller fractions of the training set (10 %, 25 %, 50 %, 100 %) and plots train RMSE vs val RMSE. You should see:

  • Very small train set: train RMSE ≈ 0, val RMSE ≫ 0 (overfits noise).
  • Full train set: train RMSE ≈ val RMSE (good fit).

This is the "learning curve" you'll formalise in S088 (bias–variance).

💡 Hint · Look at RMSE and R² on train vs val for each fraction. Overfitting shows up when train ≪ val.

(d) Production reality · 15 min

War story Kaggle · repeated across 100s of competitionsthousands of lost prizes
🔥 What broke

Teams score fantastically on the public leaderboard (val set), pop champagne, then get destroyed on the private leaderboard (test set). Root cause: they overfit to the public leaderboard by submitting hundreds of times, effectively using the public LB as another val set. When the private LB is revealed, they crash 200+ places.

🧯 The fix
Modern Kaggle strategy: trust your own local cross-validation more than the public leaderboard. If your CV says +0.001 improvement but the LB says +0.010, it's probably leaderboard overfitting. Ship the CV winner.
🎓 Lesson to steal
The test set is exactly as trustworthy as the number of times you've looked at it. Every look costs a small amount of statistical honesty. Save your looks for what matters.
War story Zillow Offers · 2021-11· 2021$881M writedown · shut down entirely
🔥 What broke

Zillow's iBuyer program used an ML model to price houses it would then buy. The training data was historical sales, but the market shifted rapidly in 2021: rising rates, changing buyer behaviour. The model kept predicting yesterday's prices, Zillow kept buying at those prices, and inventory piled up at 5–7 % below what they could sell for.

This is concept drift: the distribution the model was trained on stopped matching the distribution it was seeing at inference time. The metric (RMSE on historical val) looked great; the business metric (margin on actual sales) was catastrophic.

🧯 The fix
Zillow shut Offers down entirely, laid off 25 % of staff, took an $881M writedown. Competitors added continuous online retraining, human-in-the-loop review for large offers, and hedging on inventory carry.
🎓 Lesson to steal
Val/test scores measure "on the past." Production measures "the present." Any model deployed to a nonstationary world needs continuous evaluation on live data plus rollback triggers.
Post-mortem
War story Amazon recruiting AI · scrapped 2018· 2018unknown but significant hiring impact
🔥 What broke

Amazon trained an ML system on 10 years of engineering resumes to score new applicants. Because the training data was mostly male (industry demographics at the time), the model learned that ‘woman’, ‘women's chess club’, and certain colleges were negative signals. Amazon caught the bias and scrapped the tool.

🧯 The fix
There is no easy fix. The training labels themselves encoded past hiring bias. You cannot fix a biased-target problem by adding features — you need to redesign the problem (e.g., predict work sample scores, not ‘was this person hired’).
🎓 Lesson to steal
Your model learns your training labels' biases perfectly. If the labels are wrong (racist, sexist, obsolete), the model will amplify them at scale. Always question: are the labels themselves the right thing to predict?
Post-mortem

Where this shows up in the rest of the plan

The X/y/split/loss/metric scaffold is used in every ML session
S085 · Linear regression from scratch
Instantiate the scaffold — X and y are numeric, loss is MSE, metric is RMSE, solve with normal equations.
S086 · Logistic regression
Same scaffold, y ∈ {0,1}, loss is cross-entropy, metric is accuracy/AUC.
S087 · Regularization
Extends the loss with a penalty term — same X/y, same split, richer L.
S088 · Bias–variance
Formalises the train vs val gap you just saw in the TryIt.
S089–S091 · Trees + boosting
Same X/y matrix, non-parametric model, but split and metric machinery is identical.
S096 · MLOps & deployment
The lifecycle diagram extended into production: monitor drift, retrain on schedule, ship safely.

(e) Recall + stretch · 10 min

Recall — click each to reveal · click to reveal
★ = stretch question

Explain-out-loud test

If you can't teach these three without notes, redo the session:

  1. What is X, what is y, and what does the model do? (one sentence each)
  2. Why do we need three splits, not two? (and what each is for)
  3. What is data leakage, and what's the one habit that prevents most of it? (hint: pipelines)

What comes next

Hub: The 6-Month Learning Plan


Part of a 130-session evergreen learning series. Session structure: intuition → visual → hands-on → production war stories → recall. Duration: 90 minutes.