Underfitting vs Overfitting
What youβll learn
- the two-number diagnosis: training error and validation error, and what their gap means
- the complexity curve, and why the training half of it is nearly useless on its own
- the learning curve, and the one question only it can answer β will more data help?
- the fixes, which are opposites, and why applying the wrong one makes things worse
- how to read the measured numbers on a real curve rather than eyeballing a shape
Intuition
A model can fail in exactly two ways, and they look nothing alike.
Underfitting is a model too rigid to represent the pattern. A straight line through a curve misses low, then high, then low β and it will keep missing however much data you give it. The training error is high, and the validation error is barely worse.
Overfitting is a model flexible enough to memorise the training rows, including their noise. Training error goes to zero and validation error goes up, because the noise it learned is different noise from the noise in the new rows.
The diagnosis needs two numbers, never one:
| Training error | Validation error | Diagnosis |
|---|---|---|
| High | High, similar | Underfitting β too rigid |
| Low | Much higher | Overfitting β memorising |
| Low | Low, similar | Good fit |
| High | Lower than training | Something is wrong: a leak, a bad split, or heavy regularisation only active at training time |
That last row is the one people misread as good news.
flowchart TD A["Measure training and
validation error"] --> B{"Is training error
acceptable?"} B -->|no| C["UNDERFITTING
add capacity"] B -->|yes| D{"Is the gap large?"} D -->|yes| E["OVERFITTING
reduce capacity or add data"] D -->|no| F["Good fit
ship it"] C --> G["more features, higher degree,
weaker regularisation, longer training"] E --> H["more data, simpler model,
stronger regularisation, early stopping"]
Seeing both at once
Reading the plot
- Degree 1 produces fifty almost identical lines, all of them missing the curve. Consistent and consistently wrong. More data changes nothing.
- Degree 4 tracks the truth and the spread is modest. This is what a good fit looks like when you can see the whole distribution of fits rather than one.
- Degree 15 has an average close to the truth, but individual fits swing far from it. Any single model you happen to train is a draw from that scatter.
The right panel is the crucial insight: an overfitted model is not systematically wrong, it is unreliable. Its average is fine; its individual predictions are not.
The complexity curve
Measured on 120 points from the same generator:
| Degree | Training MSE | 5-fold CV MSE | Gap | Reading |
|---|---|---|---|---|
| 1 | 0.618 | 0.634 | 0.016 | Underfitting badly |
| 2 | 0.347 | 0.390 | 0.043 | Still underfitting |
| 3 | 0.319 | 0.354 | 0.036 | Improving |
| 4 | 0.120 | 0.139 | 0.019 | Best |
| 6 | 0.115 | 0.144 | 0.029 | Marginally worse |
| 10 | 0.112 | 0.337 | 0.225 | Overfitting |
| 15 | 0.100 | 9.669 | 9.569 | Overfitting catastrophically |
Three things worth noticing:
- Training MSE falls from 0.618 to 0.100 across the whole range and never once warns you. A model selected on training error alone would choose degree 15.
- Degrees 4 and 6 are indistinguishable β 0.139 against 0.144. Prefer the simpler one.
- Degree 15 is not slightly worse, it is 70 times worse. Overfitting does not degrade gracefully once the model has enough capacity to interpolate.
The learning curve
The complexity curve varies capacity at fixed data. The learning curve does the reverse, and it answers a different question: would collecting more data help?
The two panels answer the same question differently:
| Shape | Diagnosis | Will more data help? |
|---|---|---|
| Both curves flat at a high error | Underfitting | No. Add capacity instead. |
| Validation still falling as data grows | Variance still being reduced | Yes. Keep collecting. |
| Gap persists and validation is flat | Overfitting, saturated | No. Simplify or regularise. |
| Both converge at a low error | Good fit | Nothing to do. |
Measured on the plot: degree 1 goes from 0.614 to 0.596 β a 3% gain from ten times the data, which is another way of saying no gain. Degree 15 goes from 0.368 to 0.294, a 20% gain and still descending. Notice also that degree 15 has stopped overfitting by 200 samples: the gap that would have been enormous at 20 samples has closed. That is data doing the work regularisation would otherwise have to do.
This is a genuinely useful business answer. βShould we spend three months labelling more data?β has a defensible answer, and it is on this plot.
Worked example by hand
Four models of the same problem, each measured on the same held-out set:
| Model | Train RMSE | Validation RMSE | Gap | Gap as % of train |
|---|---|---|---|---|
| A: linear | 69,051 | 69,218 | 167 | 0.2% |
| B: depth-4 tree | 58,200 | 61,400 | 3,200 | 5.5% |
| C: unpruned tree | 0 | 70,676 | 70,676 | β |
| D: random forest | 18,476 | 50,010 | 31,534 | 171% |
Step 1 β is the training error acceptable? Against an expert baseline of about 35,530, models A and B are already failing on the training set. That settles it: they are underfitting, and no amount of regularisation will help.
Step 2 β for the rest, how big is the gap? Model Cβs training error is exactly zero, which is not an achievement but a description of what an unpruned tree does. Model D has a large gap and still the best validation score.
Step 3 β choose the fix.
- A and B: add capacity. More features, a deeper model, less regularisation.
- C: reduce capacity.
max_depthmax_depth,min_samples_leafmin_samples_leaf, or pruning. - D: more data, or mild regularisation. The gap says there is headroom; the validation score says it is still the best option available.
The trap: models A and D both need attention, and the correct actions are opposites. Applying regularisation to A β the intuitive response to βthe model is not good enoughβ β makes it worse.
Fixing each
Underfitting
| Fix | Mechanism |
|---|---|
| More features, or better ones | Gives the model something to work with |
| Higher-capacity model | Degree, depth, layers, kernel |
| Reduce regularisation | Raise CC, lower alphaalpha, raise max_depthmax_depth |
| Train longer | More epochs, more estimators |
| Remove aggressive feature selection | You may have discarded the signal |
More data does not fix underfitting. A straight line fitted to a million curved points is the same straight line.
Overfitting
| Fix | Mechanism |
|---|---|
| More training data | The most reliable fix, and usually the most expensive |
| Simpler model | Lower degree, shallower tree, fewer parameters |
| Stronger regularisation | Lower CC, raise alphaalpha, raise min_samples_leafmin_samples_leaf |
| Early stopping | Halt before the model starts memorising |
| Feature selection | Fewer columns, less to memorise |
| Ensembling | Averaging cancels variance β the whole of Phase 5 |
| Data augmentation | Synthetic variety where collecting real data is impossible |
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import KFold
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import PolynomialFeatures
rng = np.random.default_rng(4)
x = rng.uniform(0, 6, 120)
y = np.sin(1.5 * x) + 0.35 * x + rng.normal(0, 0.35, 120)
folds = list(KFold(5, shuffle=True, random_state=0).split(x))
for degree in (1, 2, 4, 10, 15):
train = ((y - np.polyval(np.polyfit(x, y, degree), x)) ** 2).mean()
cv = np.mean([
((y[va] - np.polyval(np.polyfit(x[tr], y[tr], degree), x[va])) ** 2).mean()
for tr, va in folds
])
verdict = ("underfitting" if cv > 0.3 and cv / train < 1.5
else "overfitting" if cv / train > 2
else "good fit")
print(f"degree {degree:2d} train {train:.4f} cv {cv:8.4f} {verdict}")
# degree 1 train 0.6182 cv 0.6338 underfitting
# degree 2 train 0.3472 cv 0.3896 underfitting
# degree 4 train 0.1201 cv 0.1387 good fit
# degree 10 train 0.1117 cv 0.3368 overfitting
# degree 15 train 0.1004 cv 9.6689 overfittingimport numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import KFold
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import PolynomialFeatures
rng = np.random.default_rng(4)
x = rng.uniform(0, 6, 120)
y = np.sin(1.5 * x) + 0.35 * x + rng.normal(0, 0.35, 120)
folds = list(KFold(5, shuffle=True, random_state=0).split(x))
for degree in (1, 2, 4, 10, 15):
train = ((y - np.polyval(np.polyfit(x, y, degree), x)) ** 2).mean()
cv = np.mean([
((y[va] - np.polyval(np.polyfit(x[tr], y[tr], degree), x[va])) ** 2).mean()
for tr, va in folds
])
verdict = ("underfitting" if cv > 0.3 and cv / train < 1.5
else "overfitting" if cv / train > 2
else "good fit")
print(f"degree {degree:2d} train {train:.4f} cv {cv:8.4f} {verdict}")
# degree 1 train 0.6182 cv 0.6338 underfitting
# degree 2 train 0.3472 cv 0.3896 underfitting
# degree 4 train 0.1201 cv 0.1387 good fit
# degree 10 train 0.1117 cv 0.3368 overfitting
# degree 15 train 0.1004 cv 9.6689 overfittingSee it move
Pitfalls
Training RMSE 69,051 and validation RMSE 69,218. What is the diagnosis?
A gap of 167 on 69,000 is essentially zero. The model is not memorising anything because it cannot; both errors are high for the same reason.
Show answer
B β Underfitting β the tiny gap means the model is not flexible enough to fit even the training data β A gap of 167 on 69,000 is essentially zero. The model is not memorising anything because it cannot; both errors are high for the same reason.
Your learning curves converge at a high error and flatten. Should you collect more data?
Converged curves mean the model has extracted everything it can. Add capacity or better features instead. A wide, still-narrowing gap is the shape that justifies more data.
Show answer
B β No β converged-and-high means underfitting, and more of the same data cannot help a model that cannot represent the pattern β Converged curves mean the model has extracted everything it can. Add capacity or better features instead. A wide, still-narrowing gap is the shape that justifies more data.
Training MSE falls from 0.618 at degree 1 to 0.100 at degree 15, while CV MSE goes from 0.634 to 9.669. What does the training curve tell you?
More capacity can always fit the training set at least as well. A model chosen on training error alone will always pick the most complex option available.
Show answer
B β Essentially nothing β training error falls monotonically with capacity by construction, so only the CV curve carries information β More capacity can always fit the training set at least as well. A model chosen on training error alone will always pick the most complex option available.
Your validation error is lower than your training error. What should you do?
There are benign explanations, and there are leaks. Both are worth identifying before the result is reported.
Show answer
B β Investigate β this usually indicates a leak, training-only regularisation such as dropout, or an unusually easy validation split β There are benign explanations, and there are leaks. Both are worth identifying before the result is reported.
π§ͺ Try It Yourself
Exercise 1 β Diagnose from two numbers
Exercise 2 β Build the complexity curve
Exercise 3 β Fix an underfitting model
Exercise 4 β Read a learning curve
Exercise 5 β Regularisation on the wrong patient
Recap
- Two numbers, never one. High-and-close is underfitting; low-with-a-gap is overfitting.
- Training error falls monotonically with capacity, so it carries no information on its own. On the measured curve it went 0.618 β 0.100 while CV error went 0.634 β 9.669.
- The complexity curve locates the best capacity; the learning curve says whether more data would help.
- An overfitted model is not systematically wrong β its average is fine and its individual predictions are unreliable.
- The fixes are opposites. Diagnose before acting: regularising an underfitting model makes it worse.
- Validation error below training error is a symptom to investigate, not a success.
Exercise 6 β Turn two numbers into a next action
Next
Continue to Bias vs Variance Tradeoff β the same two failures, derived as an exact decomposition of expected error into three terms.
If this helped you, consider buying me a coffee β
Buy me a coffeeWas this page helpful?
Let us know how we did
