Machine Learning·Lesson 31·14 min·0/3 exercises

Iris — and why it is too easy

The most famous dataset in the field, and one flower is worth 3.33 accuracy points

load_irismulti-classclass_weightconfusion_matrixsmall-sample noise

Watch it happen

Play it through, or step back and forth yourself.

irisFisher, 1936
rows 150features 4task 3-class
setosa
50
versicolor
50
virginica
50
dummy (most_frequent) = 0.3333 — balanced, so the floor is 1/3
from sklearn.datasets import load_iris

iris = load_iris(as_frame=True)
iris.data.shape        # (150, 4)
iris.target_names      # setosa, versicolor, virginica
Four columns: sepal length and width, petal length and width, all in centimetres. Measured by Edgar Anderson, published by Fisher as an example for a statistical method — which is a good clue about what it's for.

Ronald Fisher published these 150 flowers in 1936, and they've been the first dataset in practically every course since. Three species, four measurements each, and no missing values anywhere.

The idea

Ronald Fisher published these 150 flowers in 1936, and they have been the first dataset in practically every course since. Three species, four measurements, no missing values, and it loads from inside the scikit-learn wheel in about 0.02 seconds — no download at all.

from sklearn.datasets import load_iris

iris = load_iris(as_frame=True)
iris.data.shape       # (150, 4)
iris.target_names     # ['setosa' 'versicolor' 'virginica']
np.bincount(iris.target)   # [50 50 50]

Three classes, not two

Our chai target was binary. This is the first genuinely multi-class problem in the track, and a few things change:

  • The dummy scores 0.3333 — perfectly balanced, so the floor is 1/3 rather than the majority share.
  • The confusion matrix is 3×3, and the off-diagonal now tells you which pair gets confused.
  • Precision, recall and F1 need an average="macro" treats every class equally, "weighted" by support. With balanced classes they agree.
  • coef_ gains a row per class, and predict_proba a column per class.

scikit-learn handles multi-class automatically, which is why almost none of this needed mentioning until now.

The gap

Look at petal length by species:

setosa      max  1.9 cm
others      min  3.0 cm

There is a clear gap with nothing in it. One comparison classifies a third of the dataset perfectly:

if petal_length < 2.5:
    return "setosa"      # 50 of 50, no errors

A depth-1 decision tree on petal length alone scores 0.667: it nails setosa and then has to guess between the other two.

Which is not what real data looks like

Our chai data had rain running from 15.7% to 56.5% late — signal everywhere, certainty nowhere. Iris has a boundary you can draw on paper.

It became famous for being teachable: three tidy classes, four interpretable columns, no missing values, no leakage, no imbalance, and a visible decision boundary. Every one of those properties makes it unrepresentative of the problems you will actually be handed.

The scores

logistic regression   0.9600 ± 0.0389
kNN (k=5)             0.9600 ± 0.0249
tree, depth 2         0.9333 ± 0.0471
dummy                 0.3333

Everything works and nothing distinguishes itself — the models are within one standard deviation of each other. On a problem this easy, the choice of algorithm is the least interesting decision available.

One flower

Here is the number worth carrying away. A 20% test set is 30 flowers.

100 / 30 = 3.33 accuracy points per row

confusion matrix:  [[10  0  0]
                    [ 0 10  0]
                    [ 0  1  9]]

One mistake, in the whole test set. A model at 0.967 and a model at 1.000 differ by a single flower. There is no meaningful comparison available at that resolution, and yet "my method gets 98% on iris" is a sentence people still write.

This is lesson 8's discipline on a dataset small enough to feel it: the fold spreads (±0.039 against ±0.025) carry more information than the means.

So what is it actually for?

  • Checking your code runs. Four columns, no NaN, instant.
  • Demonstrating an API with nothing in the way.
  • Drawing a decision boundary — two features, three classes, visible on a slide.
  • Teaching multi-class metrics, since a 3×3 matrix fits in your head.

And not for comparing algorithms, benchmarking a method, or practising any of the parts that are hard in real work. It's a teaching aid, and a very good one — as long as you know that's what it is.

See it run

The lesson's code, ready to run and to fiddle with.

Putting the kettle on…

Starting up…

Worked example

not graded

Already 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, 2, 3 on the split and watching the single error move around.

Press Run — the output appears here.

Your turn

3 exercises. Write the code yourself, then press Check — a nudge and the answer are there if you want them.

Load iris and return [list(shape), class_counts, n_classes] — the shape of the feature frame, the count per class as a list, and how many classes there are.

your answer

Find the gap. Return [setosa_max_petal_length, others_min_petal_length] — the two numbers that show one comparison separates setosa perfectly.

your answer

Show the resolution problem. Split 20% stratified at random_state=0, fit a logistic pipeline, and return [n_test_rows, points_per_row, n_errors] — points rounded to 2 places.

your answer