← Machine learning with Gradio

The nearest penguin

Write a real machine-learning model yourself: to guess a new penguin's species, find the most similar penguin in the data and copy its answer.

Music apps suggest songs like the ones you play; shops suggest things bought by people like you. Many of these start from one idea: find the closest match.

Instead of writing rules, let the data decide. To guess a mystery penguin's species, find the penguin in the data whose measurements are closest, and give its species. This is called nearest neighbour, and it is a real machine-learning method. Closeness is a distance: with bill and flipper length as the two sides of a right-angled triangle, Pythagoras gives the distance between two penguins (** 2 squares a number, ** 0.5 takes the square root).

PredictRead the code and say what it will do before you run anything. A wrong guess is fine: it shows you what to look for.

Predict

nearest.py
def distance(a, b):
    return ((a["bill"] - b["bill"]) ** 2 + (a["flipper"] - b["flipper"]) ** 2) ** 0.5


print(distance({"bill": 40, "flipper": 190}, {"bill": 43, "flipper": 194}))

The bills differ by 3 and the flippers by 4. What does Pythagoras say?

What does it print?

RunRun it and compare the result with your prediction.

Run

Run it, then change the mystery penguin's measurements and run again: try 38, 185, 50, 196 and 45, 205. Which is the hardest to guess, and why?

nearest.py
import csv

penguins = []
with open("penguins.csv") as f:
    for row in csv.DictReader(f):
        penguins.append({"species": row["species"], "bill": float(row["bill_length_mm"]), "flipper": float(row["flipper_length_mm"])})


def distance(a, b):
    return ((a["bill"] - b["bill"]) ** 2 + (a["flipper"] - b["flipper"]) ** 2) ** 0.5


def nearest(new):
    best = penguins[0]
    for p in penguins:
        if distance(p, new) < distance(best, new):
            best = p
    return best


mystery = {"bill": 47.0, "flipper": 215.0}
match = nearest(mystery)
print("Nearest penguin: " + match["species"] + ", bill " + str(match["bill"]) + ", flipper " + str(match["flipper"]))
print("Distance: " + str(round(distance(match, mystery), 1)))
print("Guess: " + match["species"])
Try it yourselfYour edits are saved in this browser.

InvestigateTrace how each line of code connects to what you see.

Investigate

nearest.py
import csv

penguins = []
with open("penguins.csv") as f:
    for row in csv.DictReader(f):
        penguins.append({"species": row["species"], "bill": float(row["bill_length_mm"]), "flipper": float(row["flipper_length_mm"])})


def distance(a, b):
    return ((a["bill"] - b["bill"]) ** 2 + (a["flipper"] - b["flipper"]) ** 2) ** 0.5


def nearest(new):
    best = penguins[0]
    for p in penguins:
        if distance(p, new) < distance(best, new):
            best = p
    return best


mystery = {"bill": 47.0, "flipper": 215.0}
match = nearest(mystery)
print("Nearest penguin: " + match["species"] + ", bill " + str(match["bill"]) + ", flipper " + str(match["flipper"]))
print("Distance: " + str(round(distance(match, mystery), 1)))
print("Guess: " + match["species"])

Answers from examples.

What the distance says.

The furthest penguin, not the nearest.

Where is the "learning" in this model?

A mystery penguin's nearest match is 0.2 away; another's is 10 away. Which guess would you trust more, and why?

The mystery penguin (47, 215) is guessed as an Adelie 44 away, though a Gentoo 0.2 away is in the data. Click the line that is wrong.

ModifyChange the code on purpose and check the result.

Modify

Ask for the bill and flipper length with input().

Need a hint?

Replace the mystery line: bill = float(input("Bill length (mm)? ")), the same for flipper, then mystery = {"bill": bill, "flipper": flipper}.

When the nearest penguin is more than 10 away, print Not sure instead of a guess.

Need a hint?

If distance(match, mystery) > 10, print Not sure instead of the guess.

Try it yourselfYour edits are saved in this browser.

Ask for the mystery penguin's measurements with input().

    Run your program. This ticks when your code does all of the above.

    Print Not sure when the nearest penguin is more than 10 away.

      Run your program. This ticks when your code does all of the above.

      MakeBuild something new using what you have learned. Expect a few tries; that is normal.

      Five mystery penguins

      Guess the species of each of the five mystery penguins, and print each guess with its distance. Which guess would you not trust?

      Try it yourselfYour edits are saved in this browser.

      Guess the species of each mystery penguin, and print each guess with its distance.

        Run your program. This ticks when your code does all of the above.

        Info

        Where this leads

        How good is this model really? Testing it on penguins it already knows would be cheating: that is the next lesson.

        Flipper lengths are around 200 and bill lengths around 45. What does that do to the distance?

        For teachers

        Students write a nearest-neighbour model from scratch, measuring the distance between penguins with Pythagoras and copying the species of the closest one, then ask for measurements, add a "not sure" answer and guess five mystery penguins. About 45 minutes.

        Open the teacher guide: answers, solutions, slides and a worksheet.

        Students will be able to

        Before class

        Read the unit primer first. Nearest neighbour keeps every example and answers with the species of the closest one; the distance is Pythagoras on bill and flipper length (** 2 squares, ** 0.5 is the square root). nearest() is Data detective's "smallest so far" pattern (the bug task uses >, finding the furthest penguin). A big distance means nothing similar is known, so the guess is weak, but the model still answers: the "Not sure" task and the optional last lesson come back to this. The info question raises scale: flippers (around 200) outweigh bills (around 45) in the distance.

        Running the lesson

        1. Predict: draw the right-angled triangle with sides 3 and 4.
        2. Run: plot three penguins and the mystery on a sketch graph (bill across, flipper up).
        3. Investigate: ask which guess students would bet on, and why.
        4. Make: discuss the 60, 240 penguin: what is wrong with its guess?

        The hard part (on purpose)

        The smallest-so-far loop inside nearest(). Ask students to trace it for three penguins on paper before they fix the bug.

        When students get stuck

        Stretch and support

        Stretch: Make the three nearest penguins vote (sort by distance with sorted(penguins, key=lambda p: distance(p, mystery))[:3]).

        Support: Give students the Not sure if, and ask them only to choose the number.

        Where it leads

        Next lesson tests the model fairly, on penguins it has not seen. scikit-learn's KNeighborsClassifier (Lesson 4) is this model.

        What each step is for

        Now you can
        Next lesson3. A fair testHold back some penguins to test on: a model tested on the data it learned from looks perfect, and only new data shows how good it really is.