Python Linear and Multiple Regression

Fit simple and multiple linear regression models, read their coefficients and residuals, evaluate them on held-out data and know their limits.

Lesson 93 of 107Advanced13 min read

Linear regression predicts a number as a weighted sum of input features plus a constant:

prediction = intercept + coefficient₁ × feature₁ + coefficient₂ × feature₂ + ...

With one feature it fits a straight line; with several it's multiple regression. In Python, scikit-learn's LinearRegression finds the coefficients that make the squared prediction errors on the training data as small as possible:

Python
from sklearn.linear_model import LinearRegression
X = [[1], [2], [3], [4]]          # paint layer thickness (mm)
y = [3, 5, 7, 9]                  # drying time (hours)
model = LinearRegression().fit(X, y)
print(model.coef_, model.intercept_)   # about [2.] and 1.0

This lesson covers the model, adding features, reading residuals, evaluating on held-out data and the limits of interpretation. The examples predict paint drying times at a furniture restoration workshop. It assumes the ideas in introduction to machine learning.

Linear model

In the simple case, the model is a line: drying hours = intercept + slope × thickness. After fitting:

  • model.coef_ holds the slope: the change in predicted hours for each extra millimetre.
  • model.intercept_ holds the predicted value when every feature is zero.
  • model.predict(X_new) applies the formula to new rows.
Python
model = LinearRegression().fit([[1], [2], [3], [4]], [3, 5, 7, 9])
print(model.predict([[2.5]]))      # [6.]

"Linear" refers to the coefficients, not the shape of the data. You can model curved relationships by adding transformed features, such as thickness² or log(thickness), and the model is still linear regression, because the prediction is a weighted sum of those columns. PolynomialFeatures in scikit-learn generates such columns. The model assumes the relationship really is approximately linear in its features; when it isn't, its predictions are systematically off in some ranges.

Multiple features

Multiple regression uses several columns at once, giving each its own coefficient:

Python
# features: thickness (mm), room temperature (°C), humidity (%)
X = [[1, 20, 40], [2, 18, 55], [3, 22, 50], [2, 25, 35], [4, 19, 60], [1, 23, 45]]
y = [2.8, 6.1, 6.9, 4.2, 10.3, 2.6]
model = LinearRegression().fit(X, y)

Each coefficient estimates the effect of its feature with the others held fixed: how much drying time changes per extra millimetre at the same temperature and humidity.

That interpretation gets shaky when features are correlated. If humid days are also cold days, the model can't cleanly separate their effects, and the individual coefficients may swing wildly with small data changes even though predictions stay reasonable. Coefficients also depend on units: humidity in percent and temperature in degrees aren't directly comparable, so standardise features (see summary statistics for ML) before comparing coefficient sizes.

Fitting and residuals

Fitting chooses coefficients that minimise the sum of squared residuals, where a residual is the difference between an observed value and the model's prediction:

residual = actual − predicted

Python
predicted = model.predict(X)
residuals = [actual - p for actual, p in zip(y, predicted)]

Residuals are the most useful diagnostic you have. Plot them against predictions or against each feature: they should look like random scatter around zero. Patterns reveal problems, for example residuals that grow with thickness (the model under-predicts thick layers), a curve (the relationship isn't linear) or a few huge residuals (unusual records worth investigating).

Squaring makes large errors count heavily, so one extreme record can pull the whole line. A small training error doesn't prove anything about new data: with enough features, a model can fit its training rows almost perfectly and still predict poorly. That's why evaluation uses data the model never saw.

Evaluation limits

Evaluate on a held-out test set and report errors in meaningful units:

  • MAE (mean absolute error): average size of errors, in hours. Easy to explain.
  • RMSE (root mean squared error): also in hours, but penalises large errors more.
  • R²: the share of variation in the target explained by the model; 1 is perfect, 0 is no better than predicting the mean, and it can be negative on test data.
Python
from sklearn.metrics import mean_absolute_error, r2_score
mae = mean_absolute_error(y_test, model.predict(X_test))

Always compare with a baseline, such as predicting the training mean. Two further limits matter. Extrapolation: a model fitted on layers of 1 to 4 mm has no evidence about 15 mm layers, so don't trust predictions far outside the training range. Causation: a coefficient describes an association in the data, not proof that changing the feature would change the outcome; a hidden factor might drive both.

Independent practice and a worked check

Task: build single- and multiple-feature drying models with a held-out set and interpretable error units.

Python
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error

X_full = [[1, 20], [2, 18], [3, 22], [2, 25], [4, 19], [1, 23], [3, 17], [2, 21]]
y = [2.8, 6.1, 6.9, 4.2, 10.3, 2.6, 9.1, 4.9]
X_one = [[row[0]] for row in X_full]            # thickness only

for label, X in [("thickness only", X_one), ("thickness + temperature", X_full)]:
    model = LinearRegression().fit(X[:6], y[:6])
    mae = mean_absolute_error(y[6:], model.predict(X[6:]))
    print(f"{label:<24} test MAE {mae:.2f} hours")

Compare the two errors in hours: if adding temperature reduces the test MAE, the extra feature helps on unseen data, not just on the training rows. For the worked check, ordinary linear regression predicts a numeric value.

Reference and next practice

scikit-learn's linear models guide and regression metrics go further. Continue with logistic regression and training and testing datasets. Practise with the Python exercises and Python quiz.

Linear and Multiple Regression Summary

  • Linear model: Linear regression expresses a numeric prediction as an intercept plus weighted feature contributions.
  • Multiple features: Multiple regression combines several feature columns for the same numeric target.
  • Fitting and residuals: Fitting selects coefficients according to an objective, and residuals compare observed with predicted outcomes.
  • Evaluation limits: Assess held out numeric errors with meaningful units and compare a baseline.

Linear and Multiple Regression Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Linear and Multiple Regression in a small program

Python
from sklearn.linear_model import LinearRegression
X = [[1], [2], [3], [4]]
y = [3, 5, 7, 9]
model = LinearRegression().fit(X, y)
print(round(float(model.predict([[5]])[0]), 1))
Output
11.0
Line-by-line explanation
  1. Lines 2 to 3Four examples where drying time rises by exactly 2 hours per millimetre.
  2. Line 4fit() finds the line: slope 2, intercept 1.
  3. Line 5Predicting 5 mm extrapolates the line: 1 + 2 × 5 = 11 hours.
Example 2

Multiple regression with held-out evaluation

Python
from sklearn.linear_model import LinearRegression
from sklearn.dummy import DummyRegressor
from sklearn.metrics import mean_absolute_error, r2_score

# thickness (mm), temperature (°C), humidity (%) -> drying hours
X = [[1, 20, 40], [2, 18, 55], [3, 22, 50], [2, 25, 35], [4, 19, 60], [1, 23, 45],
     [3, 17, 65], [2, 21, 45], [4, 24, 40], [1, 18, 60], [3, 20, 55], [2, 23, 50]]
y = [2.8, 6.1, 6.9, 4.2, 10.3, 2.6, 9.1, 4.9, 8.0, 3.6, 7.8, 4.8]

X_train, y_train, X_test, y_test = X[:9], y[:9], X[9:], y[9:]
model = LinearRegression().fit(X_train, y_train)
baseline = DummyRegressor().fit(X_train, y_train)

for name, est in [("baseline", baseline), ("regression", model)]:
    pred = est.predict(X_test)
    print(f"{name:<11} MAE {mean_absolute_error(y_test, pred):.2f} h  R2 {r2_score(y_test, pred):.2f}")

names = ["thickness", "temperature", "humidity"]
print({n: round(float(c), 2) for n, c in zip(names, model.coef_)})
residuals = [round(float(a - p), 2) for a, p in zip(y_test, model.predict(X_test))]
print("test residuals:", residuals)
Output
baseline    MAE 1.83 h  R2 -0.16
regression  MAE 0.39 h  R2 0.91
{'thickness': 1.96, 'temperature': -0.15, 'humidity': 0.07}
test residuals: [-0.9, 0.01, -0.25]
Line-by-line explanation
  1. Line 10The last three records are held out and never used for fitting.
  2. Lines 14 to 16Both the baseline and the model are scored on the same unseen rows.
  3. Lines 18 to 19Coefficients give the estimated change in hours per unit of each feature, others held fixed.
  4. Lines 20 to 21Individual residuals show where the model is furthest off: it over-predicts the first test record by about 0.9 hours. The baseline's negative R² means it does worse than predicting the test mean.

Common Linear and Multiple Regression Mistakes

Trusting predictions far outside the training range

Don't
model.fit([[1], [2], [3], [4]], [3, 5, 7, 9])
print(model.predict([[30]]))      # 61 hours for a 30 mm layer: no data supports this
Do
lo, hi = 1, 4                     # range seen in training
thickness = 30
if not lo <= thickness <= hi:
    print("Outside the fitted range; collect data before predicting")

Reading a coefficient as a cause

Don't
"The humidity coefficient is 0.06, so lowering humidity will make paint dry faster."
Do
"Holding thickness and temperature fixed, higher humidity is associated with longer
drying in this data. A controlled test would show whether changing humidity causes it."

Linear and Multiple Regression in Real Projects

Regression in practice

Linear regression is often the first model tried on numeric prediction problems: estimating delivery times, house prices, energy use or sales. Its coefficients are easy to explain, it trains instantly, and it's a strong baseline for more complex models such as gradient boosting. Regularised versions, Ridge and Lasso in scikit-learn, shrink coefficients to reduce overfitting and handle correlated features better.

For statistical inference, such as confidence intervals and p-values for coefficients, analysts use statsmodels, which reports the uncertainty around each estimate. scikit-learn focuses on prediction quality.

Linear and Multiple Regression FAQ

How do I do linear regression in Python?

With scikit-learn: model = LinearRegression().fit(X, y), where X is a 2-D table of features and y the target. Read model.coef_ and model.intercept_, and call model.predict(X_new). For statistical summaries with p-values, use statsmodels.

What is the difference between simple and multiple linear regression?

Simple linear regression uses one feature and fits a straight line. Multiple linear regression uses several features, each with its own coefficient, fitting a plane or higher-dimensional surface.

What is a good R² score?

It depends on the problem: physical measurements may reach 0.95, while human behaviour data might be useful at 0.3. Judge R² on held-out data and alongside an error in real units, such as MAE, and a baseline.

What are residuals?

The differences between actual values and the model's predictions. Plotting them shows whether errors are random, which is good, or follow a pattern, such as growing with a feature, which means the model is missing something.

Why must X be a 2-D list in scikit-learn?

scikit-learn expects one row per example and one column per feature, even when there's only one feature. Write [[1], [2], [3]] rather than [1, 2, 3], or reshape a NumPy array with array.reshape(-1, 1).

Linear and Multiple Regression Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Multiple choiceeasy

What kind of target does ordinary linear regression predict?

Multiple choicemedium

Which review concern is valid for linear and multiple regression?

Linear and Multiple Regression Quiz

2 questions to check what you learned.

  1. What kind of target does ordinary linear regression predict?

    • Only a category label
    • A numeric value
    • Python ignores the distinction
  2. Which statement correctly describes fitting and residuals?

    • Fitting selects coefficients according to an objective, and residuals compare observed with predicted outcomes.
    • Only the example output matters, not the rule
    • Every operation has the same behavior