Two students prepare for an exam. One memorises last year's question paper word for word — every answer, in order. The other understands the concepts. On last year's paper the memoriser scores 100%. On this year's, they are lost.
That is overfitting, and it is the most-asked concept in ML placement interviews for a good reason: it is the failure mode that every model, every algorithm and every project has to deal with.
The three fits
Underfitting — the model is too simple to capture the pattern. It performs poorly on training data and on new data.
Good fit — it captures the underlying trend without chasing individual points. Slightly better on training than on test, which is normal and expected.
Overfitting — the model has learned the noise as well as the signal. Near-perfect on training data, poor on anything new.
Diagnosing from two numbers
You need only the training score and the test score, and the diagnosis is entirely in the gap.
| Train | Test | Diagnosis |
|---|---|---|
| 98% | 71% | Overfitting — large gap, high variance |
| 64% | 63% | Underfitting — no gap, both poor, high bias |
| 87% | 85% | Healthy — small gap, both reasonable |
| 99.9% | 99.7% | Suspicious — on a hard problem, suspect a bug |
Two habits follow. Always compute both numbers — a candidate who reports only training performance has told you nothing. And always ask whether the test score is good relative to a baseline: 85% is excellent if a simple rule gets 60%, and worthless if the rule gets 84%.
The bias-variance tradeoff
The formal framing behind those two failures, and a guaranteed interview question.
Bias is error from wrong assumptions — the model is too simple to represent the truth. Fitting a straight line to a curved relationship has high bias no matter how much data you give it.
Variance is sensitivity to the particular training sample — train on a slightly different set and you get a very different model. High-variance models chase noise.
Increasing model complexity lowers bias and raises variance. Total error is minimised somewhere in between — and validation data is what finds that point for you, not intuition.
💡 The analogy that lands in an interview: high bias is an archer who consistently hits the same spot away from the bullseye. High variance is one whose arrows scatter all over the target. You want tight and centred, and improving one usually costs a little of the other.
Fixing each one
| Overfitting (high variance) | Underfitting (high bias) |
|---|---|
| More training data — the most reliable fix | Better features — usually the highest-return fix |
| Simpler model: shallower trees, fewer features | More capable model: linear → tree → ensemble |
| Add regularisation (L1/L2, dropout) | Reduce regularisation |
| Early stopping at the validation minimum | Train longer |
| Cross-validation instead of one split | Add feature interactions or polynomial terms |
| Remove duplicate rows inflating the training score | Check the features contain the signal at all |
That last cell on the right matters more than it looks. If a model underfits no matter what you do, the honest possibility is that the features simply don't contain the answer — and no algorithm rescues that. Teams lose months to model tuning on problems the data cannot support.
Cross-validation
One train-test split gives you one number, and with a few hundred rows that number depends heavily on which rows happened to land where. K-fold cross-validation splits the data k ways, trains k times, and averages.
from sklearn.model_selection import cross_val_score
scores = cross_val_score(model, X, y, cv=5, scoring="f1")
print("folds:", scores.round(3))
print("mean :", scores.mean().round(3), "±", scores.std().round(3))Result
Two things to read there. The mean is a more trustworthy estimate than any single split. And the spread is information — that fourth fold at 0.641 is worth investigating, because a wide variance across folds usually means the data is heterogeneous or the model is unstable.
Use stratified k-fold for classification so each fold keeps the class balance. And for time-series data, use a time-aware split — training on future data to predict the past is something production can never do.
Regularisation
The general idea: penalise complexity, so the model only takes on complexity that genuinely pays for itself in reduced error.
| Technique | Applies to | Effect |
|---|---|---|
| L1 (Lasso) | linear models | can drive coefficients to exactly zero — feature selection |
| L2 (Ridge) | linear models | shrinks coefficients toward zero, keeps all features |
| max_depth, min_samples_leaf | trees | stops the tree memorising individual rows |
| Dropout | neural networks | randomly deactivates neurons during training |
| Early stopping | anything iterative | stop at the validation minimum — free, and effective |
The L1-versus-L2 distinction is asked often: Lasso can zero features out; Ridge shrinks but keeps them. Choose L1 when you suspect many features are useless, L2 when features are correlated and you want them shrunk together.
Wait — my model got 99.9%. Is that good?
On a problem experts find hard? Almost certainly not. Extraordinary results demand extraordinary scrutiny, and near-perfect scores are usually a bug rather than a breakthrough.
The usual culprit is data leakage — information from the answer sneaking into the features. Four ways it happens:
# 1. A FEATURE THAT ENCODES THE ANSWER
# Predicting churn using "account_closed_date" — recorded when
# the customer churned. The model is reading the answer.
# TEST: would this value be known, with this value, on the day
# I make the prediction?
# 2. PREPROCESSING BEFORE SPLITTING
scaler.fit_transform(df) # ✗ learns from test rows
X_train, X_test = train_test_split(df)
X_train, X_test = train_test_split(df) # ✓ split first
scaler.fit(X_train); scaler.transform(X_test)
# 3. DUPLICATE ROWS SPLIT ACROSS TRAIN AND TEST
# The model has literally seen the test row before.
# 4. RANDOM SPLIT ON TIME-DEPENDENT DATA
# Trains on the future to predict the past. Split by time.Leakage is the single most common reason a brilliant offline model fails in production, because the leaked feature does not exist — or does not have that value — at prediction time.
🎯 Selection-round radar: "What is overfitting?" is near-certain. Give the definition, then the diagnosis (high training score, low test score — the gap is the signal), then three fixes. And if they follow up with a 99% result on a hard problem, the expected answer is suspect data leakage, not congratulations.
Common mistakes
- Reporting only the training score.
- Using the test set repeatedly for tuning — it stops being held out.
- Preprocessing (scaling, imputing, encoding) before splitting.
- Random splits on time-dependent data.
- Duplicate or near-duplicate rows straddling train and test.
- Treating a near-perfect score as success rather than as a bug report.
- Adding model complexity when the features don't contain the signal.
Quick recap
| Concept | One-liner |
|---|---|
| Overfitting | memorises noise; high train, low test — the gap is the signal |
| Underfitting | too simple; both scores low, no gap |
| Bias vs variance | wrong assumptions vs sensitivity to the sample; complexity trades them |
| Cross-validation | k splits averaged; the spread across folds is information too |
| Regularisation | penalise complexity; L1 zeroes features, L2 shrinks them |
| Data leakage | the answer sneaking into the features — the cause of most 99% models |
| The leakage test | would this value be known, with this value, at prediction time? |
Practice Zone — PYQs from real selection rounds
Six MCQs, then two tasks: diagnose four models from their scores, and find every leak in a real pipeline.
What is overfitting?
Asked in

A model scores 62% on training data and 61% on test data. This is:
Asked in

What is the bias-variance tradeoff?
Asked in

Why use k-fold cross-validation instead of one train-test split?
Asked in

What is the difference between L1 (Lasso) and L2 (Ridge) regularisation?
Asked in

A model achieves 99.8% test accuracy on a hard problem. What should you check first?
Asked in

Hands-on tasks:
Diagnose each and prescribe a fix. (A) train 98%, test 71%. (B) train 64%, test 63%. (C) train 87%, test 85%. (D) train 99.9%, test 99.7% on a problem experts call hard.
Asked in

This churn pipeline gives 99% accuracy. Find every reason it will fail in production.
Asked in

df = pd.read_csv("customers.csv")
scaler = StandardScaler()
df[num_cols] = scaler.fit_transform(df[num_cols]) # (1)
df = df.fillna(df.mean()) # (2)
X = df.drop("churned", axis=1)
y = df["churned"]
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42) # (3)
model.fit(X_train, y_train)
print(model.score(X_test, y_test)) # 0.99FAQ
How big a train-test gap is acceptable?
There is no universal number, and the honest answer says why: it depends on the problem's difficulty and how much data you have. A few points is normal. Twenty is a clear problem. What matters more than the gap is whether the test score is good enough for the business and better than the baseline.
Why do I need a validation set as well as a test set?
Because every time you look at the test set and change something, you leak a little information into your decisions. Tune on validation, and touch the test set once at the end. In practice this is the discipline most people skip, and it is why reported scores are often optimistic.
Can more data always fix overfitting?
It is the most reliable fix, but not unlimited. More data helps a model distinguish signal from noise. It does not help if the features are wrong, if the labels are inconsistent, or if the problem is genuinely unpredictable — some outcomes have a ceiling no amount of data raises.
Next lesson: the numbers you report, and why accuracy is usually the wrong one — Lesson 6: Evaluation Metrics →


