Linear regression
ml basics
Linear regression is usually the first model anyone learns, and sections 3.1 to 3.3 of An Introduction to Statistical Learning (ISLP) cover it well. It’s worth learning properly, because it’s simple, fast, easy to explain to a business user, and the starting point for many other models.
This post continues the regression vs classification example: predicting how many OTC trades will fail to settle on a given day.
The idea
You have some days. For each day you know how many trades were booked, and how many failed. Plot them, and they roughly form a line: more trades, more fails. Linear regression finds the one straight line that fits the points best, so you can read off a forecast for any number of trades.
A straight line has two numbers. In the notation of An Introduction to Statistical Learning (ISLP), equations 3.1 and 3.2, with hats marking numbers estimated from data:
β̂ and ŷ, what the model estimatesy, the actual valueRSS and TSS, the error and the spread
| Symbol | Meaning | In our example |
|---|---|---|
| the input (feature) | thousand trades booked that day | |
| the prediction (“y-hat”) | predicted number of fails | |
| (“beta-one-hat”) | the slope: how much goes up when goes up by 1 | extra fails per extra 1,000 trades |
| the intercept: the value of when | the line’s starting level |
What “best” means: least squares
For each day, the line makes a prediction . The real value is . The difference is the residual, the miss.
Linear regression picks the line that makes the residual sum of squares (RSS) as small as possible (ISLP equation 3.3):
Why square them? Three reasons. A miss above the line and a miss below don’t cancel out. Big misses count much more than small ones. And squaring gives a neat formula for the answer, with no searching needed. This method is called ordinary least squares (OLS).
For one input, the best slope and intercept are (ISLP equation 3.4):
where and (read “x-bar”, “y-bar”) are the averages.
Plain meaning of the slope formula: the top measures how and move together. When a day has more trades than usual, does it also have more fails than usual? The bottom measures how much moves on its own. Their ratio is “how much moves per unit of ”. (The top part, divided by , is the covariance, which gets its own post in this series.)
Worked example: five days by hand
| Day | Trades (k) | Fails | product | |||
|---|---|---|---|---|---|---|
| 1 | 8 | 70 | −4 | −25 | 100 | 16 |
| 2 | 10 | 85 | −2 | −10 | 20 | 4 |
| 3 | 12 | 92 | 0 | −3 | 0 | 0 |
| 4 | 14 | 110 | 2 | 15 | 30 | 4 |
| 5 | 16 | 118 | 4 | 23 | 92 | 16 |
| Average / Sum | 242 | 40 |
Reading it: each extra 1,000 trades brings about 6 more fails. A day with 13,000 trades: fails expected.
Be careful with the intercept. It says that a day with zero trades has 22.4 fails, which makes no sense. We never saw a day anywhere near zero trades. A line is only trustworthy inside the range of data it learned from. Using it far outside that range is called extrapolation, and it’s how linear models embarrass people.
The dotted lines on the left are the residuals. The fitted line is the one where the squares of those dotted lines add up to the smallest possible total, here 23.9.
How good is the fit? R²
(“R squared”, ISLP equation 3.17) answers: what share of the ups and downs in does the line explain?
- TSS (total sum of squares) is how much varies around its own average: the error you’d make if you ignored and always guessed the average.
- RSS (residual sum of squares) is the error left over after using the line.
For the five days: TSS and RSS , so
The line explains 98.4% of the day-to-day variation in fails. means no better than guessing the average. means perfect.
More than one input
Real days differ in more than trade count. Cross-border trades fail more often, so add the share of cross-border trades as a second input:
Now the “line” is a flat surface in three dimensions, but the idea is the same: find the numbers that make the squared misses smallest.
I made up a year of 250 business days (the hidden rule was 20 + 6 per thousand trades + 150 times the cross-border share, plus random noise). Trained on 187 of them:
| Learned | Hidden rule | |
|---|---|---|
| Intercept | 13.2 | 20 |
| Per 1,000 trades | 6.53 | 6 |
| Per unit of cross-border share | 148.5 | 150 |
The model got close to the hidden rule from noisy data alone. Not exact: with noise, the estimates are always a bit off, and they get closer with more data.
Reading : a cross-border share 10 percentage points higher (say 30% instead of 20%) means more fails, with the trade count held the same. That last part matters. In multiple regression, each number is the effect of one input while the others stay fixed.
On the 63 test days the model never saw, was 0.786. With trade count alone it was only 0.383. The second input more than doubled how much of the variation the model explains.
The matrix form (for revision)
With many inputs, the formula is written with matrices. Put the inputs in a matrix (one row per day, plus a column of 1s for the intercept) and the answers in a vector . The best coefficients are:
This comes from the normal equations (Murphy, Probabilistic Machine Learning, chapter 11). ISLP doesn’t print the matrix form, because it needs matrix algebra. On the five days it gives exactly , the same as the hand calculation. In practice, libraries solve it with more numerically stable methods than inverting the matrix, but the answer is the same.
The code
import numpy as np
from sklearn.linear_model import LinearRegression
x = np.array([8, 10, 12, 14, 16]) # thousand trades
y = np.array([70, 85, 92, 110, 118]) # fails
# By hand
b1 = ((x - x.mean()) * (y - y.mean())).sum() / ((x - x.mean()) ** 2).sum()
b0 = y.mean() - b1 * x.mean()
print(b0, b1) # 22.4 6.05
# With scikit-learn: same answer
model = LinearRegression().fit(x.reshape(-1, 1), y)
print(model.intercept_, model.coef_) # 22.4 [6.05]
print(model.predict([[13]])) # [101.]
When linear regression goes wrong
- The relationship isn’t a straight line. If fails jump sharply above some volume, a line will miss it. (Decision trees, the next post, handle this.)
- Extrapolation. Never trust the line far outside the data, like the “22 fails on a day with no trades”.
- Outliers. Because misses are squared, one extreme day (a market outage) can pull the line a long way.
- Inputs that move together. If two inputs are strongly linked (trade count and number of counterparties, say), the model can’t tell their effects apart, and the individual numbers become unstable, even when the predictions are fine.
- Correlation is not causation. The slope says fails and volume move together. It doesn’t prove one causes the other.
Summary
| Idea | Formula | Remember it as |
|---|---|---|
| The line | Start level plus slope times input | |
| Best fit | minimise | Least squares |
| Slope | How they move together ÷ how moves alone | |
| Intercept | The line passes through the averages | |
| Fit quality | Share of the variation explained | |
| Many inputs | The normal equation |
Next
Decision trees: a model that asks a series of yes/no questions instead of drawing a line, and can follow patterns a straight line can’t.
References
- James, Witten, Hastie, Tibshirani and Taylor, An Introduction to Statistical Learning, with Applications in Python (Springer, 2023), sections 3.1 to 3.3: the model (equations 3.1, 3.2), RSS (3.3), least-squares estimates (3.4), (3.17)
- Kevin P. Murphy, Probabilistic Machine Learning: An Introduction (MIT Press, 2022), chapter 11: the normal equations
- scikit-learn: ordinary least squares