Maya needs to estimate a delivery time. She has three completed trips: 1 km took 6 minutes, 2 km took 12, and 3 km took 18. What should she estimate for a new 4 km trip?
We will use one small example from Sachin, a fictional company. You only need multiplication to follow along.
A model is a calculation with a setting
Our calculator multiplies distance by pace, the minutes needed for each kilometer. This reusable calculation is the model. Its pace is the adjustable number, also called a parameter.
estimated time = distance × pace
Learning, also called training or fitting, uses completed examples to choose that number. Fitting means choosing the model’s setting to match the known answers as closely as possible. Here, it finds a pace of 6 min/km.
Fitted means trained: the model’s setting has been chosen from the examples. Prediction uses that trained calculation for a new input: 4 × 6 = an estimated 24 minutes.
Why is this called supervised learning?
Each example includes an input and its known answer. The distance is the input. The recorded travel time is the known answer, also called the target or label. These answers guide training.
We choose the calculation’s form. Training calculates its pace from the records. The model does not understand roads or traffic, and the new trip’s actual time is still unknown.
Try it with different examples
Change a recorded time, then train again. Or move the new distance and use the model you already have.
The rule is time = distance × pace, with zero minutes at zero distance. Fitting chooses one pace for all the records, so the line may miss individual points.
| Distance | Known time |
|---|---|
| 1 km | min |
| 2 km | min |
| 3 km | min |
The original examples are already fitted.
Fitted pace: 6 min/km. Moving the distance uses this setting; it does not train again.
Inspect the fitted calculation
Training examples: 1 km → 6 min, 2 km → 12 min, 3 km → 18 min
pace = (1 × 6 + 2 × 12 + 3 × 18) / (1² + 2² + 3²)
= 84 / 14
= 6 min/km
Prediction: 4 × 6 = 24 minThis pace gives the smallest total squared error for a line through zero. A miss is the difference between a recorded time and the model’s time. Square each miss and add them to compare paces. Displayed values are rounded; calculations use full precision.
Try Slower trips and train again. The fitted pace becomes 12 min/km, so the same 4 km question gives 48 minutes. Then try One unusual trip: a single changed answer also shifts the fitted line.
This example predicts travel time from distance alone. It omits preparation and waiting, and assumes zero time at zero distance. Fitting these three records does not establish accuracy on future trips.
One quick check
A fitted model uses 6 minutes per km. You give it 5 km instead of 4 km, without training again. Did it learn something new?
Choose one answer.
The chapter in one infographic
Examples, fitting, prediction, and what changes when the data changes.
Imagine two trip estimates: one is 2 minutes too low, the other 2 minutes too high. We write the errors as +2 and −2. Both should count as mistakes.
Squaring means multiplying a number by itself: 2 × 2 = 4 and (−2) × (−2) = 4. The two mistakes add up to 8. Cubing uses three copies: 2 × 2 × 2 = 8. Our errors become +8 and −8, which add up to 0 and hide both mistakes.
Squaring also makes big mistakes count more: a 4-minute miss scores 16, while a 2-minute miss scores 4. Add the scores for all trips to get the total squared error. In point 4, the lowest point on the curve is the pace with the smallest total.
Other scoring rules can work too. Removing minus signs before cubing also works, but gives big mistakes even more weight. This example uses squares.
Code and sources
Run the prewritten code
Optional: Node.js 20 or newer, with no extra packages. Copy the full source below into learning-from-examples.mjs. It uses the same calculation as the playground.
node learning-from-examples.mjsLearned pace: 6 min/km
New 4 km trip: 24 min
New 5 km trip, same model: 30 min
After learning from slower trips: 12 min/km
Same 4 km question: 48 minFull source
/** A deliberately small supervised model: minutes = pace * kilometers. */
export const TRIPS = Object.freeze([
Object.freeze({ id: "T1", km: 1, minutes: 6 }),
Object.freeze({ id: "T2", km: 2, minutes: 12 }),
Object.freeze({ id: "T3", km: 3, minutes: 18 }),
]);
export const PRESETS = Object.freeze([
{ id: "ordinary", label: "Original trips", minutes: [6, 12, 18] },
{ id: "slower", label: "Slower trips", minutes: [12, 24, 36] },
{ id: "unusual", label: "One unusual trip", minutes: [6, 12, 36] },
]);
export function tripsForPreset(id) {
const preset = PRESETS.find((entry) => entry.id === id);
if (!preset) throw new RangeError("Choose a known trip preset.");
return TRIPS.map((trip, index) => ({ ...trip, minutes: preset.minutes[index] }));
}
export function fitPace(trips) {
if (!Array.isArray(trips) || !trips.length) throw new RangeError("Training needs completed trips.");
let distanceTime = 0;
let distanceSquared = 0;
const examples = trips.map((trip) => {
if (!Number.isFinite(trip.km) || trip.km <= 0 || !Number.isFinite(trip.minutes) || trip.minutes < 0) {
throw new RangeError("Use positive distances and nonnegative, finite trip times.");
}
distanceTime += trip.km * trip.minutes;
distanceSquared += trip.km * trip.km;
return { ...trip };
});
// The least-squares solution for a line constrained to pass through zero.
const pace = distanceTime / distanceSquared;
return { pace, examples, squaredError: squaredError(examples, pace) };
}
export function predictMinutes(model, km) {
if (!Number.isFinite(model?.pace) || model.pace < 0 || !Number.isFinite(km) || km < 0) {
throw new RangeError("Prediction needs a fitted pace and a nonnegative, finite distance.");
}
return model.pace * km;
}
export function squaredError(trips, pace) {
return trips.reduce((total, trip) => total + (trip.minutes - pace * trip.km) ** 2, 0);
}
export function formatNumber(value) {
return Number(value.toFixed(1)).toString();
}
export const ORIGINAL_MODEL = fitPace(TRIPS);
export const SLOWER_MODEL = fitPace(tripsForPreset("slower"));
// Fictional data. One input: kilometers. One target: travel time in minutes.
const model = fitPace(TRIPS);
const newDistance = 4;
console.log(`Learned pace: ${formatNumber(model.pace)} min/km`);
console.log(`New ${newDistance} km trip: ${formatNumber(predictMinutes(model, newDistance))} min`);
// Changing the new input uses the existing rule. It does not train again.
console.log(`New 5 km trip, same model: ${formatNumber(predictMinutes(model, 5))} min`);
// Changing training answers and fitting again produces a different rule.
const slowerModel = fitPace(tripsForPreset("slower"));
console.log(`After learning from slower trips: ${formatNumber(slowerModel.pace)} min/km`);
console.log(`Same ${newDistance} km question: ${formatNumber(predictMinutes(slowerModel, newDistance))} min`);
// Your turn: change one trip's minutes, fit again, and predict a 4 km trip.
Sources and implementation notes
Definitions follow scikit-learn’s introduction to fitting and prediction and Google’s introduction to linear models. The scoring explanation follows Google’s guide to prediction errors. The implementation directly solves a one-feature least-squares model with no intercept. The infographic compares settings; it does not depict an iterative training trace.
Next: Chapter 2: Regression →


