← Teacher guide

Rules by hand

Students meet the Palmer Penguins data, guess species with hand-written if rules, measure accuracy on 342 penguins, look at the mistakes, tune the rules, and write rules of their own with a third measurement.

Machine learning with Gradio · Models by hand · about 45 minutes · Open the student lesson

Classroom resources

Load these into Waypoints Prepare: choose Load URL and paste the copied address, or download the file and import it. In Prepare, the worksheet's Teacher edition shows the answers; the student copy hides them.

Students will be able to

Timing

Predict and Run 10 min · Investigate 10 min · Modify 15 min · Make 10 min

Before class

Read the unit primer first. This course runs in the Python playground (real Python in the browser, Pyodide); later lessons load scikit-learn, which takes several seconds the first time, so open the site's Check your school page once on a student device at school. penguins.csv is the Palmer Penguins data (CC0): 342 penguins of three species with bill length and depth, flipper length, body mass, sex, island and year (2 penguins with no measurements are left out). The loader is the same csv.DictReader pattern as Data detective, with float() (the bug task forgets it). The rules reach 95% accuracy; the mistakes are mostly Adelies with long bills guessed as Chinstrap. The second Investigate question sets up the course: a person chose 206, and machine learning finds such things from data.

Running the lesson

  1. Predict: trace guess(50.0, 196) on the board, rule by rule.
  2. Run: ask for a show of hands: who thinks 95% is good? What about for a medical test?
  3. Modify: tally the mistakes by species on the board.
  4. Make: compare accuracies across the class.

The hard part (on purpose)

Using the mistakes to improve the rules. Ask students what the wrong guesses have in common before they change a number.

When students get stuck

What you will seeA question to askThe fix
TypeError: '>' not supported between instances of 'str' and 'int'.Were the measurements turned into numbers when they were read?float(row["bill_length_mm"]).
KeyError: 'bill_depth_mm' in the Make.Is it read from row, or from the penguin dictionary?Read row["bill_depth_mm"] in the loader and store it, such as "depth": float(...).
The accuracy is above 100%.Is correct counted once per penguin?Add 1 only inside the if, once per penguin.

Answers to the checks

  1. Predict: What does the second line print?
    Chinstrap. 196 is not over 206, so it is not Gentoo; 50.0 is over 44, so the rule says Chinstrap.
  2. What accuracy means: The rules get 95% right. What does that mean?
    95 of every 100 penguins get the right species
    Accuracy is right answers divided by all answers. Here 324 of 342 penguins: 95%.
  3. Who chose 206?: Where does the number 206 come from?
    Someone chose it by looking at the data: most Gentoos have longer flippers than that
    A person picked it. Learning a number like this from data, instead of picking it, is what machine learning does.
  4. Spot the bug: This stops with TypeError: '>' not supported between instances of 'str' and 'int'. Click the line that is wrong.
    line 6
    Values from a CSV are text. The measurements need float() when they are read, as in the Run step.
  5. Where this leads: Writing rules by hand gets harder with more measurements and more species. What would help?
    A program that finds the rule or the answer from the examples itself: machine learning
    Machine learning finds patterns from examples instead of a person choosing every number. Next lesson: a model that learns by looking at the most similar penguin.

Solutions

One possible solution for each task. Other correct programs are fine.

Modify › The mistakes

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 guess(bill, flipper):
    if flipper > 206:
        return "Gentoo"
    if bill > 44:
        return "Chinstrap"
    return "Adelie"


correct = 0
for p in penguins:
    if guess(p["bill"], p["flipper"]) == p["species"]:
        correct = correct + 1
print(str(correct) + " of " + str(len(penguins)) + " right: " + str(round(100 * correct / len(penguins))) + "%")

for p in penguins:
    g = guess(p["bill"], p["flipper"])
    if g != p["species"]:
        print(p["species"] + " guessed as " + g + ": bill " + str(p["bill"]) + ", flipper " + str(p["flipper"]))

Modify › Tune the rules

Open task: any program that does what the step asks.

rules of your own

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"]), "depth": float(row["bill_depth_mm"])})


def guess(p):
    if p["depth"] < 16:
        return "Gentoo"
    if p["bill"] > 44:
        return "Chinstrap"
    return "Adelie"


correct = 0
for p in penguins:
    if guess(p) == p["species"]:
        correct = correct + 1
print(str(round(100 * correct / len(penguins))) + "% right")

Stretch and support

Stretch: Print a table of guesses against real species (a confusion matrix) with a dictionary of dictionaries.

Support: Give students the loop that prints mistakes, and ask them only to write the if.

Exit ticket

What does it mean that the rules are 95% accurate on the penguins?

They give the right species for 95 of every 100 penguins in the data (324 of 342).

What each step is for

Where it leads

Next lesson builds a model that learns from the examples themselves: nearest neighbour.