Skip to content
OrionStats
Module 11 · ML Foundations · How models are evaluated

Machine learning foundations — prediction vs explanation, validation, overfitting and leakage

The discipline that separates useful models from impressive-looking wrong ones — correct splits, validation, metrics, over/underfitting, leakage, and knowing when ML is unnecessary.

Advanced80 min
Learning objectives
  • Distinguish prediction from explanation and choose the goal explicitly
  • Design train/validation/test splits, including time-based splits
  • Choose evaluation metrics for regression and classification and compare with baselines
  • Recognise overfitting, underfitting and data leakage — and prevent them
  • Decide when machine learning is the wrong tool

Prediction vs explanation

  • Explanation asks why: which factors are associated with churn, by how much, with what uncertainty? Simple, interpretable models (regression) and careful causal reasoning.
  • Prediction asks what will happen for a new case: which subscribers will churn next month? Accuracy on new data matters most; complex models are acceptable if they are validated and monitored.

A model can predict well without explaining causes (it may exploit correlations), and a good explanatory model may predict modestly. State the goal before choosing methods.

When ML is useful — and when it is unnecessary

ML helps when there are many cases, a repeated decision, enough historical labelled data, and patterns too complex for rules. It is unnecessary or harmful when:

  • a simple rule or SQL query answers the question ("customers inactive 90 days");
  • there are few cases or the decision is one-off;
  • labels are unreliable or the future will differ fundamentally from the past;
  • the organisation cannot act on the predictions or maintain the model.

AI assistants (LLMs) can draft SQL and code quickly, but they can invent columns, misunderstand grain or produce subtly wrong logic. Treat generated code as an untested junior colleague's work: read it, run it on known cases, reconcile results — and never paste confidential data into tools your organisation has not approved.

Splitting data

Set Purpose
Training Fit model parameters
Validation Choose features, model type, hyperparameters
Test Final, untouched estimate of performance on new data

Cross-validation (k-fold) rotates the validation fold for more stable estimates on small data. For time-ordered problems (forecasts, churn next month), split by time: train on the past, validate on later periods. Random splits leak future patterns into training.

Metrics

Regression: MAE (average absolute error, in units), RMSE (penalises large errors), MAPE (% error — undefined at zero actuals), WAPE (Σ|error| ÷ Σ actual — robust for retail), R².

Classification: confusion matrix (TP, FP, TN, FN); precision = TP ÷ (TP + FP); recall = TP ÷ (TP + FN); F1; ROC-AUC (ranking quality); calibration (do predicted 30% risks happen 30% of the time?).

Worked example — 1,000 subscribers, 100 churn. A model flags 150; 60 of them churn. TP = 60, FP = 90, FN = 40, TN = 810. Precision = 60 ÷ 150 = 40%; recall = 60 ÷ 100 = 60%; accuracy = 870 ÷ 1,000 = 87% — lower than the 90% of "nobody churns". Accuracy is misleading for rare events; choose metrics that match the business cost of errors.

Always compare with a baseline: majority class, last value, seasonal naive, a simple rule.

Overfitting and underfitting

  • Underfitting: the model is too simple; poor on training and test data (high bias).
  • Overfitting: the model memorises training noise; excellent on training, worse on test (high variance).
import pandas as pd, numpy as np
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import roc_auc_score
subs = pd.read_csv("telecom/subscribers.csv")
X = pd.get_dummies(subs[["contract_type", "payment_method", "region", "acquisition_channel", "plan_id"]].astype(str), drop_first=True)
X["age"] = subs["age"]; y = subs["churned"]
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, random_state=7, stratify=y)
for depth in [1, 3, 6, 12, None]:
    m = DecisionTreeClassifier(max_depth=depth, random_state=7).fit(Xtr, ytr)
    print(f"max_depth={str(depth):>4}  train AUC={roc_auc_score(ytr, m.predict_proba(Xtr)[:,1]):.3f}  test AUC={roc_auc_score(yte, m.predict_proba(Xte)[:,1]):.3f}")
max_depth=   1  train AUC=0.574  test AUC=0.579
max_depth=   3  train AUC=0.608  test AUC=0.613
max_depth=   6  train AUC=0.640  test AUC=0.617
max_depth=  12  train AUC=0.792  test AUC=0.560
max_depth=None  train AUC=0.988  test AUC=0.507

As depth grows, training AUC climbs toward 1 while test AUC stalls and then falls — the signature of overfitting. Choose complexity on validation performance, not training performance.

Data leakage

Leakage = information available during training that would not be available at prediction time. It produces excellent offline metrics and failure in production.

Leak Example
Target leakage Using "number of support tickets in the final month" to predict churn — tickets about cancellation happen because of churn
Future data Features computed over the full period, including after the prediction date
Preprocessing leakage Scaling or imputing with statistics computed on the whole dataset before splitting
Duplicate entities Same customer in train and test with near-identical rows
Label proxies A "cancellation_reason" column that is only filled for churners

Prevention: define a prediction date; build every feature only from data before it; split by time; fit preprocessing inside a pipeline on training data only; be suspicious of any feature that looks "too good".

Practice

A churn model flags 200 customers; 80 of them actually churn. In total 160 customers churned. What is the model's recall in %?

Log in to answer and get feedback

Predicting next-month churn, a feature 'number of tickets in the last 30 days before churn date' gives test AUC 0.97. What is most likely?

Log in to answer and get feedback

Train AUC 0.99, test AUC 0.51. Diagnosis?

Log in to answer and get feedback

For a monthly sales forecast, how should you split training and test data?

Log in to answer and get feedback

Summary

  • Decide whether you need prediction or explanation; use ML only when it beats simpler approaches and can be acted on.
  • Split train/validation/test — by time for temporal problems; compare with baselines.
  • Choose metrics matching the business cost of errors; accuracy misleads on rare events.
  • Overfitting = great training, worse test; leakage = information from the future — prevent it by design.