Model Evaluation & Selection
Level 5 — Mastery (cross-domain: probability, optimization, coding) Time limit: 90 minutes Total marks: 60
Answer all three questions. Show all derivations. Where code is requested, write clean, runnable Python (NumPy/scikit-learn conventions accepted).
Question 1 — Bias–Variance Decomposition & Learning-Curve Prognosis (22 marks)
(a) For squared-error regression, let the data be generated by with , . Let be an estimator trained on random dataset . Prove the pointwise decomposition
State clearly every independence/zero-mean assumption you use. (8 marks)
(b) Consider -nearest-neighbours regression on a fixed test point with neighbours whose true values are all locally, and i.i.d. noise variance . Show that the variance term of the prediction is and argue how bias behaves as grows. Use this to explain why acts as a complexity/regularization knob (with = more complex). (6 marks)
(c) A team reports: training RMSE , validation RMSE , and both curves have flattened as training-set size increased. The irreducible noise std is estimated at . Diagnose the regime (underfit/overfit/well-fit), justify using the numbers, and give two concrete, distinct remedies consistent with your diagnosis. Explain why adding more data alone would (or would not) help. (8 marks)
Question 2 — Threshold Metrics, ROC/PR Geometry, and a Proof (20 marks)
A binary classifier is evaluated on a test set with positives and negatives. At a given threshold the confusion counts are .
(a) Starting from definitions, derive expressions for precision, recall (TPR), and FPR in terms of these counts. Then prove that if the class prior decreases (dataset becomes more imbalanced) while TPR and FPR are held fixed, precision monotonically decreases. Give the precision formula purely in terms of TPR, FPR, and . (8 marks)
(b) A model produces scores. Sorted by descending score the true labels are:
Compute the AUC by counting concordant positive–negative pairs (ties none). Show the pair count and the normalisation. (6 marks)
(c) For the same score ordering, an operating point is chosen after the top-3 scores are predicted positive. Build the confusion matrix and compute accuracy, precision, recall, and . Then state, with justification, whether this threshold is Pareto-optimal on the PR curve relative to the top-2 threshold. (6 marks)
Question 3 — Nested Cross-Validation & Honest Model Selection (18 marks)
(a) Explain precisely why selecting hyperparameters by the same -fold CV score that is then reported as the model's generalization estimate produces an optimistically biased estimate. Frame it as a multiple-comparisons / selection-bias argument. (6 marks)
(b) Write pseudocode (or Python) for nested cross-validation with an outer 5-fold loop and inner 3-fold grid search over a hyperparameter grid G. Your code must return an unbiased generalization estimate and clearly separate the selection loop from the evaluation loop. (7 marks)
(c) A practitioner uses standard -fold CV on a dataset where each patient contributes multiple correlated rows, and also does feature selection (top- by correlation with the target) once on the full dataset before CV. Identify the two distinct leakage/pitfalls, explain the direction of the resulting bias, and give the corrected protocol for each. (5 marks)
Answer keyMark scheme & solutions
Question 1
(a) Bias–variance proof (8 marks)
Let . Write Expand into three groupings by inserting : Square and take expectation over and :
- (zero-mean noise). (1)
- is deterministic . (1)
- . (1)
Cross terms vanish:
- (noise indep. of training set, zero mean). (1.5)
- : test noise at is independent of (trained on , disjoint from test noise), and . (1.5)
- since . (1)
Hence result. Assumptions stated: zero-mean noise, noise independent of , . (1)
(b) kNN variance (6 marks)
Prediction where locally , i.i.d. .
- . (3)
- Bias: as grows, neighbours span a larger region where varies, so averages over differing values → bias grows with . (2)
- Thus small = low bias / high variance = complex model; large = smooth/regularized. is the complexity knob. (1)
(c) Diagnosis (8 marks)
- Large gap: val train → high variance / overfitting. (2)
- Train RMSE is only slightly above irreducible floor ; model fits training data near the noise floor but generalizes poorly → confirms variance-dominated, low bias. (2)
- Curves have flattened ⇒ more data will not close the gap much (learning curve plateaued); adding data alone has limited benefit. (2)
- Two remedies (any two distinct): (i) increase regularization / reduce model complexity; (ii) feature selection / dimensionality reduction; (iii) ensembling/bagging to reduce variance; (iv) early stopping. (2)
Question 2
(a) Derivation + monotonicity proof (8 marks)
- Precision , Recall/TPR , FPR . (2)
- Substitute , : Divide by , with , : (3)
- Monotonicity: write . As , , denominator , so precision (TPR, FPR fixed, both positive). Hence strictly decreasing in the imbalance. (3)
(b) AUC by pair counting (6 marks)
Labels descending: positions of positives = {1,2,4}, negatives = {3,5,6}. AUC . Count concordant pairs (positive ranked above negative):
- pos@1: beats negs at 3,5,6 → 3
- pos@2: beats 3,5,6 → 3
- pos@4: beats 5,6 (not 3) → 2
Total concordant , out of . (4) (2)
(c) Top-3 operating point (6 marks)
Top-3 predicted positive = positions {1,2,3}; labels there = {1,1,0}.
- TP=2 (pos at 1,2), FP=1 (neg at 3), FN=1 (pos at 4), TN=2 (negs at 5,6). (2)
- Accuracy ; Precision ; Recall ; . (2)
- Top-2 threshold: TP=2, FP=0 → Precision , Recall . Compared to top-3 (Prec .667, Recall .667): top-2 has equal recall but higher precision, so top-3 is dominated / NOT Pareto-optimal. (2)
Question 3
(a) Optimistic bias (6 marks)
- Choosing the hyperparameter with the best CV score means maximizing over many noisy estimates. The maximum of noisy estimates is biased high (its expectation exceeds the true best). (3)
- The winning config partly won by fitting the noise/idiosyncrasies of these particular folds → the reported CV score is contaminated by the selection, no longer an unbiased estimate of generalization. It is a multiple-comparisons/"winner's curse" bias. (3)
(b) Nested CV (7 marks)
from sklearn.model_selection import KFold
import numpy as np
def nested_cv(X, y, model_factory, G, fit_score):
outer = KFold(5, shuffle=True, random_state=0)
outer_scores = []
for tr, te in outer.split(X): # evaluation loop
# --- inner: model selection only ---
inner = KFold(3, shuffle=True, random_state=1)
best_g, best_val = None, -np.inf
for g in G:
vals = []
for itr, iva in inner.split(X[tr]):
m = model_factory(g).fit(X[tr][itr], y[tr][itr])
vals.append(fit_score(m, X[tr][iva], y[tr][iva]))
if np.mean(vals) > best_val:
best_val, best_g = np.mean(vals), g
# --- refit on full outer-train, score on untouched outer-test ---
m = model_factory(best_g).fit(X[tr], y[tr])
outer_scores.append(fit_score(m, X[te], y[te]))
return np.mean(outer_scores), np.std(outer_scores)Marks: inner loop selects only (2), outer test never seen during selection (3), refit + return mean±std (2).
(c) Leakage pitfalls (5 marks)
- Grouped data leakage: rows from the same patient appear in both train and validation folds → info leaks, optimistic bias. Fix: use
GroupKFold/StratifiedGroupKFoldkeyed on patient ID. (2.5) - Feature selection before CV (selection leakage): correlations computed on full data (incl. validation) → optimistically biased. Fix: put feature selection inside the CV pipeline, refit on each training fold only. (2.5)
[
{"claim":"kNN averaging variance is sigma^2/k",
"code":"k,s=symbols('k s',positive=True); var=k*s**2/k**2; result = simplify(var - s**2/k)==0"},
{"claim":"AUC = 8/9 for the given ranking",
"code":"pos=[1,2,4]; neg=[3,5,6]; c=sum(1 for p in pos for n in neg if p<n); result = Rational(c,len(pos)*len(neg))==Rational(8,9)"},
{"claim":"Top-3 F1 = 2/3",
"code":"TP,FP,FN=2,1,1; P=Rational(TP,TP+FP); R=Rational(TP,TP+FN); F1=2*P*R/(P+R); result = F1==Rational(2,3)"},
{"claim":"Precision decreases as prior pi decreases (fixed TPR,FPR)",
"code":"pi,tpr,fpr=symbols('pi tpr fpr',positive=True); prec=tpr*pi/(tpr*pi+fpr*(1-pi)); d=diff(prec,pi); result = simplify(d.subs({tpr:Rational(1,2),fpr:Rational(1,4),pi:Rational(1,3)}))>0"}
]