Always free. For everyone.
Course outline
Module 19 of 20 · AI & research

Make responsible model decisions

Inspect group errors, challenge explanations, and protect sensitive records. This module has 3 lessons and takes about 1h 30m. Each lesson has a practice exercise that runs real Python in your browser and a short quiz.

Start module 19 in the Learning Lab
LESSON 1 OF 3

Compare errors across groups

30 minHealthcare
WHAT YOU WILL DO

Calculate group-level recall and show why a single average can hide uneven performance.

A fictional appointment-support model flags visits that may need a reminder. Compare its mistakes for two clinic sites, rather than relying only on overall accuracy. These synthetic site labels describe operational groups and contain no patient records.

Recall measures how many actual positive cases the model catches: true positives divided by true positives plus false negatives. Return no value when a group has no actual positive examples; reporting zero would confuse missing evidence with poor performance.

A difference between sites is a signal to investigate, not proof of its cause. Examine sample size, data quality, calibration, access, and the consequences of each error. Choosing a fairness criterion needs affected communities and domain expertise, not just a formula.

See it in action

example.pyPython 3
rows = [
    ("A", 1, 1), ("A", 1, 1), ("A", 1, 0), ("A", 0, 0),
    ("B", 1, 1), ("B", 1, 0), ("B", 1, 0), ("B", 0, 0),
]  # site, actual support need, predicted flag
for group in sorted({row[0] for row in rows}):
    subset = [row for row in rows if row[0] == group]
    tp = sum(actual == 1 and predicted == 1 for _, actual, predicted in subset)
    fn = sum(actual == 1 and predicted == 0 for _, actual, predicted in subset)
    recall = tp / (tp + fn) if tp + fn else None
    print(group, "n:", len(subset), "TP:", tp, "FN:", fn, "recall:", recall)
Keep this in mind

Report who experiences errors, how often, and how much evidence each metric has.

LESSON 2 OF 3

Challenge a model explanation

30 minEnergy
WHAT YOU WILL DO

Measure permutation importance on held-out data and distinguish prediction from causation.

A fictional energy model uses occupancy and a random sensor channel to predict demand. To inspect reliance on a feature, shuffle that feature in the held-out rows and measure how much prediction error increases.

Shuffling breaks the feature's relationship with the target while keeping its individual values. Repeat it because one random shuffle can be misleading. Fit the model on training rows, and calculate importance on separate test rows.

Permutation importance describes this model on this dataset. It does not establish that changing a feature causes the target to change. Correlated features can share information, making either one appear less important when shuffled alone.

See it in action

example.pyPython 3
import numpy as np

rng = np.random.default_rng(19)
X = rng.normal(size=(100, 2))
y = 4 * X[:, 0] + rng.normal(0, 0.1, 100)
train, test = X[:70], X[70:]
design = np.column_stack([np.ones(len(train)), train])
weights = np.linalg.lstsq(design, y[:70], rcond=None)[0]
def predict(rows):
    return np.column_stack([np.ones(len(rows)), rows]) @ weights
baseline = np.mean((predict(test) - y[70:]) ** 2)
for feature in range(2):
    increases = []
    for repeat in range(10):
        shuffled = test.copy()
        shuffled[:, feature] = rng.permutation(shuffled[:, feature])
        increases.append(np.mean((predict(shuffled) - y[70:]) ** 2) - baseline)
    print("Feature", feature, "mean MSE increase:", round(float(np.mean(increases)), 3))
Keep this in mind

Explain model behaviour with evidence, and avoid turning predictive importance into causal claims.

LESSON 3 OF 3

Minimise data and validate inputs

30 minHealthcare
WHAT YOU WILL DO

Use an allowlist to create an operations dataset and reject invalid records.

A fictional clinic dashboard needs site and waiting time, but does not need names, phone numbers, or free-text notes. Data minimisation means retaining only fields needed for a defined task. An allowlist is easier to review than trying to anticipate every sensitive field to remove.

The function below validates a small input contract and returns only approved fields. It rejects negative waiting times and booleans, which Python otherwise treats as numbers. It also checks site names against the sites expected in this teaching dataset.

Removing direct identifiers is not the same as anonymisation. Combinations of details can still identify a person, and hashing an identifier does not automatically make a record anonymous. This example uses invented data and teaches a coding pattern, not compliance certification.

See it in action

example.pyPython 3
def clean_record(record):
    site = record.get("site")
    wait = record.get("wait_minutes")
    if site not in {"A", "B"}:
        raise ValueError("Unknown site")
    if type(wait) not in (int, float) or not 0 <= wait <= 480:
        raise ValueError("Waiting time must be a number from 0 to 480")
    return {"site": site, "wait_minutes": float(wait)}

fictional = {"name": "Example Person", "phone": "000-000", "site": "A",
              "wait_minutes": 25, "notes": "Invented text"}
print(clean_record(fictional))
try:
    clean_record({"site": "A", "wait_minutes": -4})
except ValueError as error:
    print("Rejected:", error)
Keep this in mind

Keep only necessary fields, validate their meaning, and do not confuse fewer identifiers with anonymity.

ABOUT THE LEARNING LAB

Free, open and run by a nonprofit.

This page is part of Python to AI, a free course of 20 modules and 60 lessons in the engineering.fit( ) Learning Lab. The Learning Lab is built and run by engineering.fit( ), a nonprofit founded by Abdullateef Opeyemi Bakare that helps African engineering students gain research experience. You do not need an account or pay a fee to learn.

Course outline · Project lab · Visit engineering-fit.org