Diabetes — a low ceiling, reported honestly
R² 0.48 is the answer, and saying so is the deliverable
load_diabetespre-scaled featuresR² ceilingssplit variancereporting limitsWatch it happen
Play it through, or step back and forth yourself.
from sklearn.datasets import load_diabetes d = load_diabetes(as_frame=True) d.data.columns # age sex bmi bp s1 s2 s3 s4 s5 s6 d.target.describe() # 25 to 346, mean 152
442 diabetes patients, ten measurements at baseline, and a target: disease progression a year later. It is a genuinely hard prediction, and that turns out to be the point.
The idea
442 diabetes patients, ten measurements taken at baseline, and a target: a quantitative measure of disease progression one year later. Higher is worse.
d = load_diabetes(as_frame=True)
d.data.columns # age sex bmi bp s1 s2 s3 s4 s5 s6
d.target # 25 to 346, mean 152It is a genuinely hard prediction, and that turns out to be the point of the lesson.
Already scaled
d.data.mean() # every column: -0.000000
d.data.std() # every column: 0.0476The columns arrive centred and scaled. Convenient — coefficients are comparable out of the box, and ridge's penalty is applied fairly (lesson 15).
And genuinely lossy: the raw units are gone. You cannot say "each extra point of BMI adds three units of progression", because there are no BMI points any more. A pre-processed dataset is a set of decisions somebody else made — check for it, and prefer the raw version when you can get it.
R² 0.482
plain linear 0.4823 ± 0.0493
ridge (alpha=1) 0.4822 ± 0.0489
random forest (200) 0.4239 ± 0.0501
dummy (mean) 0.0000That is not a bad model. It is most of what ten routine measurements can tell you about where a disease will be in a year. The instinct to treat "R² below 0.5" as failure is a habit picked up from textbook datasets, where the answer is usually engineered to be findable.
And that really is the ceiling
The forest scores worse. So the missing 0.52 is not a modelling failure you can fix with more flexibility — it's irreducible noise plus information these ten columns simply do not contain: diet, adherence, genetics, everything that happened during the intervening year.
This is the fourth dataset in a row where the linear model wins. That isn't a coincidence about this track — it's what tabular data usually looks like, and it's the reason lesson 21 said to fit a linear model and a boosted one on every problem.
Report it in something people can use
guessing the mean MAE 62.2
our model MAE 45.2
target sd 77.1, range 25 to 346"R² 0.48" tells a technical reader something. "Typical error drops from 62 to 45 units" tells everybody something — about a 27% cut in typical error.
Lesson 17's rule applied: report R² and an error in real units. Here the target's units are arbitrary, so the ratio does the work.
One honest warning about small data
5-fold cross-validated R² 0.482
single held-out test R² 0.358Same data, same model, same code. 0.12 of R² from nothing but which 110 rows landed in the test set.
Lesson 3 measured four accuracy points of seed luck on 900 rows. This is the same phenomenon on 442, where it is much worse — and it's why the cross-validated 0.482 ± 0.049 is the number to trust. On small data a single held-out score is close to anecdote.
The deliverable is the ceiling
The most useful sentence you can write about this dataset isn't about a model at all:
"These ten measurements cap out around R² 0.48. Linear and ridge reach it; a random forest does worse. Effort should go into collecting better measurements, not into trying another algorithm."
That's a finding, and it saves whoever reads it a month. To support it you need:
- a flexible model that does no better — evidence it's not a capacity problem;
- a learning curve (lesson 9) — evidence more rows wouldn't help either;
- the cross-validated number with its spread, not one split.
Saying "I got it to 0.48 and here is why that's the limit" is a much stronger result than "I got it to 0.48" — and a far more honest one than quietly trying algorithms until the test set flatters you.
See it run
The lesson's code, ready to run and to fiddle with.
Putting the kettle on…
Starting up…
Worked example
not gradedAlready written and ready to go — press Run to see what it does, then change a number, a column name, anything, and run it again.
trytrying random_state 1..5 on the split and watching the test R2 swing.
Your turn
3 exercises. Write the code yourself, then press Check — a nudge and the answer are there if you want them.
Confirm the columns arrive pre-scaled. Return [mean_of_column_means, mean_of_column_stds], rounded to 6 and 4 places.
Show it's a ceiling. Return [ridge_r2, forest_r2] — 5-fold R² for Ridge(alpha=1) and a 200-tree forest, rounded to 4 places. The forest should be lower.
Show how noisy one split is on 442 rows. Return [cross_validated_r2, single_split_test_r2] at random_state=0, rounded to 4 places.
