A New Kind of Question
Our first example was cat-or-dog: pick a category. But a huge share of real problems ask for a number instead:
- How much will this house sell for?
- How many views will this video get?
- What temperature will it be tomorrow?
Predicting a number is called regression. Let’s use a friendly example the whole way through: predict a house’s price from its size.
Look at the Data First
Imagine you collect real sales. Each house becomes a dot: its size along the bottom, its price up the side.
The dots don’t line up perfectly, but the trend is obvious, bigger houses cost more. The cloud slopes upward.
Your job is to draw a line through that cloud. Once you have it, you can predict the price of any house, even ones you’ve never seen.
The Model Is Just a Line
A straight line is described by two numbers:
- is the slope: how much the price climbs for each extra unit of size. We call it a weight.
- is the intercept: the base price where the line starts. We call it a bias.
That’s the entire model. Those two numbers, and , are the “pile of numbers” from note 1. A house-price model is literally just a good and a good .
And making a prediction is dead simple: take a size, multiply by , add .
On the graph, a prediction is just: go up from the size, hit the line, read across to the price.
Which Line Is “Best”?
Here’s the problem. There are infinitely many lines you could draw. Which one is right?
Intuitively, the best line passes closest to all the dots. So we measure the miss. Watch how:
Three steps turn “how wrong is this line?” into a single number:
- For each dot, take the gap between the real price and the line’s prediction. That gap is the error (or residual).
- Square each gap.
- Average all the squared gaps.
That final number is the Mean Squared Error (MSE).
Why square the gaps? Two good reasons:
- It makes every error positive, so misses above and below the line can’t cancel out.
- It punishes big misses much harder than small ones, so the line really tries to avoid being wildly off.
Low MSE means the line hugs the data. High MSE means it’s way off. MSE is the loss for linear regression.
The Payoff
Now look at what we’re holding:
- a model with parameters , and
- a loss (MSE) that scores how wrong any choice of and is.
We already know exactly what to do with that. It’s a loss we want to shrink, so we reach for the tool from the last note: gradient descent. Start with a random junk line, feel which way to nudge and to lower the MSE, and step downhill. The line swings and slides into place until it hugs the data.
This is the first real model. Its parameters are and , its loss is MSE, and it is trained by gradient descent. The three ingredients from note 1, now made concrete.
And a lovely bonus: the MSE landscape for linear regression is a perfect single bowl, one global minimum with no shallow traps. So here, gradient descent is guaranteed to find the one best line. No getting stuck.
One Quick Extension
Real houses have more than size: bedrooms, age, location. No problem. Just add more weights:
It is still just a weighted sum plus a bias. And that shape, a weighted sum of inputs, is the single most important pattern in all of machine learning.
Hold on to it. A neuron, which we meet soon, is exactly this line, with one small twist on top.
Try it in Python
Last note you used gradient descent to find one number. A line needs two: a slope w and an intercept b. Same tool, one extra knob, and you have your first model that learns from real data. Pure Python, no libraries, and try each step before you reveal it.
The data
Five houses, each with a size and a price. The prices trend upward with size, and we want the line price = w * size + b that passes closest to all five dots:
Here is the data we will work with:
sizes = [1, 2, 3, 4, 5]
prices = [3, 5, 6, 8, 9]Step 1: predict, and score the miss
Your task. Write predict(size, w, b) for the line, and mse(w, b) that returns the mean squared error: for every house, take the gap between the real price and the prediction, square it, then average over all the houses.
Hint: loop over the data, add up each squared gap, then divide by how many houses there are.
Reveal the answer
def predict(size, w, b):
return w * size + b
def mse(w, b):
total = 0
for i in range(len(sizes)):
prediction = predict(sizes[i], w, b)
gap = prices[i] - prediction
total = total + (gap ** 2)
return total / len(sizes)mse(w, b) is the wrongness meter for a whole line. A junk line scores high, the best-fit line scores low:
print(mse(0, 0)) # 43.0 a flat line at zero, terrible
print(mse(1.5, 1.7)) # 0.06 the best-fit line, tiny errorStep 2: feel each knob
Here is the twist. Last note there was one knob, so one slope. A line has two knobs, so we feel two slopes, one for w and one for b. Same poking trick as before, but poke one knob at a time while holding the other still.
Your task. Write slope_for_w(w, b) and slope_for_b(w, b). Each one pokes its own knob a hair up and down and measures how the MSE changed.
Reveal the answer
def slope_for_w(w, b):
poke = 0.0001
higher = mse(w + poke, b)
lower = mse(w - poke, b)
change = higher - lower
distance = 2 * poke
return change / distance
def slope_for_b(w, b):
poke = 0.0001
higher = mse(w, b + poke)
lower = mse(w, b - poke)
change = higher - lower
distance = 2 * poke
return change / distanceslope_for_w only nudges w, and slope_for_b only nudges b. Each knob gets its own slope.
Step 3: fit the line
Now run gradient descent, but step both knobs downhill each round.
Your task. Start at w = 0, b = 0, step_size = 0.03, and loop about 400 times, nudging each knob against its own slope.
Reveal the answer
w = 0.0
b = 0.0
step_size = 0.03
for i in range(400):
slope_w = slope_for_w(w, b)
slope_b = slope_for_b(w, b)
w = w - (step_size * slope_w)
b = b - (step_size * slope_b)
print(f"w = {w:.2f} b = {b:.2f} mse = {mse(w, b):.2f}")Output:
w = 1.51 b = 1.68 mse = 0.06 Starting from a flat line (MSE 43), it swings and slides until it hugs the data at w ≈ 1.5, b ≈ 1.7. You just trained your first real model: its parameters are w and b, its loss is MSE, and it learned them by gradient descent.
And here there is no getting stuck. The MSE landscape for a line is a single smooth bowl, so gradient descent always finds the one best fit.