Lesson 04
Linear Regression
Predict a number with LinearRegression: fit a line, read coef_ and intercept_, add more features, and check the fit with the R squared score.
Regression predicts a number, such as a score. Linear regression assumes each feature pushes the answer up or down by a fixed amount per unit. With one feature that is a straight line: score equals intercept plus slope times hours. fit chooses the slope and intercept that make the squared misses as small as possible.
One feature, one straight line
After fitting, the line is stored on the model. coef_ holds one slope per feature and intercept_ is the score the line gives at zero hours. Names ending in an underscore are always things the model learned.
import numpy as np
import pandas as pd
rng = np.random.default_rng(27)
learners = pd.DataFrame({
"hours": rng.uniform(1, 12, 200).round(1),
"practice": rng.integers(0, 41, 200),
"video_minutes": rng.integers(0, 3001, 200),
"track": rng.choice(["Python", "Data", "Web"], 200),
})
bonus = learners["track"].map({"Python": 0, "Data": 6, "Web": -5})
noise = rng.normal(0, 6, 200)
learners["score"] = (
22 + learners["hours"] * 3.4 + learners["practice"] * 0.55 + bonus + noise
).clip(0, 100).round()
learners["passed"] = (learners["score"] >= 60).astype(int)
from sklearn.linear_model import LinearRegression
model = LinearRegression().fit(learners[["hours"]], learners["score"])
print("slope:", model.coef_.round(2))
print("intercept:", round(model.intercept_, 2))Output:
slope: [3.4]
intercept: 34.17Predict new learners
predict plugs each new row into the line. Doing the arithmetic by hand gives the same numbers, which is a good way to see there is no magic.
import numpy as np
import pandas as pd
rng = np.random.default_rng(27)
learners = pd.DataFrame({
"hours": rng.uniform(1, 12, 200).round(1),
"practice": rng.integers(0, 41, 200),
"video_minutes": rng.integers(0, 3001, 200),
"track": rng.choice(["Python", "Data", "Web"], 200),
})
bonus = learners["track"].map({"Python": 0, "Data": 6, "Web": -5})
noise = rng.normal(0, 6, 200)
learners["score"] = (
22 + learners["hours"] * 3.4 + learners["practice"] * 0.55 + bonus + noise
).clip(0, 100).round()
learners["passed"] = (learners["score"] >= 60).astype(int)
from sklearn.linear_model import LinearRegression
model = LinearRegression().fit(learners[["hours"]], learners["score"])
newcomers = pd.DataFrame({"hours": [3.0, 6.0, 9.0]})
print(model.predict(newcomers).round(1))
print((model.intercept_ + model.coef_[0] * newcomers["hours"]).round(1).tolist())Output:
[44.4 54.5 64.7]
[44.4, 54.5, 64.7]More features, one coefficient each
Add practice and the model learns a weight for each column. Each weight is the change in score for one more unit of that feature while the others stay the same.
import numpy as np
import pandas as pd
rng = np.random.default_rng(27)
learners = pd.DataFrame({
"hours": rng.uniform(1, 12, 200).round(1),
"practice": rng.integers(0, 41, 200),
"video_minutes": rng.integers(0, 3001, 200),
"track": rng.choice(["Python", "Data", "Web"], 200),
})
bonus = learners["track"].map({"Python": 0, "Data": 6, "Web": -5})
noise = rng.normal(0, 6, 200)
learners["score"] = (
22 + learners["hours"] * 3.4 + learners["practice"] * 0.55 + bonus + noise
).clip(0, 100).round()
learners["passed"] = (learners["score"] >= 60).astype(int)
from sklearn.linear_model import LinearRegression
X = learners[["hours", "practice"]]
model = LinearRegression().fit(X, learners["score"])
for name, weight in zip(X.columns, model.coef_):
print(f"{name}: {weight:.2f} points per unit")
print(f"intercept: {model.intercept_:.2f}")Output:
hours: 3.53 points per unit
practice: 0.56 points per unit
intercept: 21.58R squared with score
For regressors, score returns R squared: 1.0 is a perfect fit, 0 is no better than always guessing the average. Measure it on the test set.
import numpy as np
import pandas as pd
rng = np.random.default_rng(27)
learners = pd.DataFrame({
"hours": rng.uniform(1, 12, 200).round(1),
"practice": rng.integers(0, 41, 200),
"video_minutes": rng.integers(0, 3001, 200),
"track": rng.choice(["Python", "Data", "Web"], 200),
})
bonus = learners["track"].map({"Python": 0, "Data": 6, "Web": -5})
noise = rng.normal(0, 6, 200)
learners["score"] = (
22 + learners["hours"] * 3.4 + learners["practice"] * 0.55 + bonus + noise
).clip(0, 100).round()
learners["passed"] = (learners["score"] >= 60).astype(int)
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
X = learners[["hours", "practice"]]
y = learners["score"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model = LinearRegression().fit(X_train, y_train)
print("train R squared:", round(model.score(X_train, y_train), 3))
print("test R squared: ", round(model.score(X_test, y_test), 3))Output:
train R squared: 0.778
test R squared: 0.706Train and test are fairly close. A straight line has only three numbers to learn here, so it cannot memorise individual learners the way a deep tree can; the small gap is mostly which rows happened to land in the test set.
A line never stops
The learned rule is only trustworthy inside the range it saw. Ask about 40 hours a week and the line happily predicts a score above 100.
import numpy as np
import pandas as pd
rng = np.random.default_rng(27)
learners = pd.DataFrame({
"hours": rng.uniform(1, 12, 200).round(1),
"practice": rng.integers(0, 41, 200),
"video_minutes": rng.integers(0, 3001, 200),
"track": rng.choice(["Python", "Data", "Web"], 200),
})
bonus = learners["track"].map({"Python": 0, "Data": 6, "Web": -5})
noise = rng.normal(0, 6, 200)
learners["score"] = (
22 + learners["hours"] * 3.4 + learners["practice"] * 0.55 + bonus + noise
).clip(0, 100).round()
learners["passed"] = (learners["score"] >= 60).astype(int)
from sklearn.linear_model import LinearRegression
model = LinearRegression().fit(learners[["hours", "practice"]], learners["score"])
extreme = pd.DataFrame({"hours": [40.0], "practice": [20]})
print(model.predict(extreme).round(1))
print("largest hours seen:", learners["hours"].max())Output:
[174.]
largest hours seen: 12.0Key takeaways
-
LinearRegression predicts a number as intercept plus weight times each feature
-
coef_ has one weight per feature; intercept_ is the value at all zeros
-
Attributes ending in _ are learned during fit
-
score gives R squared for regressors; check it on test data
-
Predictions outside the training range are guesses
-
Previous: Training and Test Sets
Loading playground…
Check your understanding
Linear Regression Quiz
What does regression predict?
1 / 10