Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Linear Regression

Simple Linear Regression predicts a continuous value using one input feature by fitting a straight line: where:

  • = intercept
  • = slope
  • = predicted output

The goal is to find the line that minimizes the sum of squared errors:


Intuition

We want the “best” straight line through the data.

  • If , the line goes upward
  • If , the line goes downward
  • tells where the line cuts the -axis

For a dataset with one feature: we add a bias column of 1s:

Then the parameters are computed using the Normal Equation: where:


Short and Clean Code

import numpy as np
import matplotlib.pyplot as plt

class SimpleLinearRegression:
    def __init__(self):
        self.intercept_ = 0.0
        self.coef_ = 0.0
        self.r2_ = 0.0

    def fit(self, X, y):
        X = np.asarray(X).reshape(-1, 1)
        y = np.asarray(y).reshape(-1, 1)

        Xb = np.c_[np.ones((len(X), 1)), X]
        theta = np.linalg.inv(Xb.T @ Xb) @ Xb.T @ y

        self.intercept_ = theta[0, 0]
        self.coef_ = theta[1, 0]

        y_pred = Xb @ theta
        ss_res = np.sum((y - y_pred) ** 2)
        ss_tot = np.sum((y - y.mean()) ** 2)
        self.r2_ = 1 - ss_res / ss_tot
        return self

    def predict(self, X):
        X = np.asarray(X).reshape(-1, 1)
        return self.intercept_ + self.coef_ * X

X = np.array([1,2,3,4,5,6,7,8,9,10])
y = np.array([2,4,5,4,5,7,8,9,10,12])

model = SimpleLinearRegression().fit(X, y)
y_pred = model.predict(X)

print("Intercept:", round(model.intercept_, 4))
print("Slope:", round(model.coef_, 4))
print("R^2:", round(model.r2_, 4))

plt.scatter(X, y, label="Data")
plt.plot(X, y_pred, label="Regression line")
plt.xlabel("X")
plt.ylabel("y")
plt.title("Simple Linear Regression")
plt.legend()
plt.show()

Output Meaning

From this code, the fitted line is approximately:

So:

  • intercept
  • slope

This means:

  • when , predicted
  • for every increase of 1 in , increases by about

The score is approximately: which means the model explains about 95.25% of the variance in the target.


Step-by-Step Algorithm

Step 1: Prepare the data

We start with:

X = np.array([1,2,3,4,5,6,7,8,9,10])
y = np.array([2,4,5,4,5,7,8,9,10,12])

Concept:

  • is the input feature
  • is the actual output

Dataset pairs:


Step 2: Add the bias column

To learn both intercept and slope together, we transform into:

Code:

Xb = np.c_[np.ones((len(X), 1)), X.reshape(-1, 1)]

Concept:

  • first column of 1s handles the intercept
  • second column stores the feature values

Step 3: Compute parameters using the Normal Equation

Equation:

Code:

theta = np.linalg.inv(Xb.T @ Xb) @ Xb.T @ y.reshape(-1, 1)

This gives:

So:

Meaning:


Step 4: Predict values

For each input, substitute into:

Code:

y_pred = self.intercept_ + self.coef_ * X.reshape(-1, 1)

Let us compute a few predictions manually.

For :

For :

For :

For :

So the model predictions are approximately:


Step 5: Measure performance using

The coefficient of determination is:

Where:

  • = residual sum of squares
  • = total sum of squares
  • = mean of actual

Code:

ss_res = np.sum((y - y_pred) ** 2)
ss_tot = np.sum((y - y.mean()) ** 2)
self.r2_ = 1 - ss_res / ss_tot

For this dataset:

Interpretation:

  • close to 1 means strong fit
  • close to 0 means poor fit

Code Explanation: Concept -> Equation -> Code

1. Store model parameters

Concept: We need to remember the learned intercept, slope, and model score.

Code:

class SimpleLinearRegression:
    def __init__(self):
        self.intercept_ = 0.0
        self.coef_ = 0.0
        self.r2_ = 0.0

Meaning:

  • intercept_ stores
  • coef_ stores
  • r2_ stores

2. Convert input into column form

Concept: Matrix equations require and in proper shapes.

Code:

X = np.asarray(X).reshape(-1, 1)
y = np.asarray(y).reshape(-1, 1)

Meaning:

  • reshape(-1, 1) makes data a column vector

Example:


3. Add the bias term

Concept: The intercept must be part of the matrix multiplication.

Equation:

Code:

Xb = np.c_[np.ones((len(X), 1)), X]

This builds:


4. Learn the best-fit line

Concept: Choose parameters that minimize squared error.

Equation:

Code:

theta = np.linalg.inv(Xb.T @ Xb) @ Xb.T @ y

This is the heart of the algorithm.

Then:

self.intercept_ = theta[0, 0]
self.coef_ = theta[1, 0]

This maps:


5. Predict outputs

Concept: Once parameters are known, plug them into the line equation.

Equation:

Code:

y_pred = Xb @ theta

or in predict():

return self.intercept_ + self.coef_ * X

Both do the same thing.


6. Evaluate model fit

Concept: Compare predictions with actual values.

Equation:

Code:

ss_res = np.sum((y - y_pred) ** 2)
ss_tot = np.sum((y - y.mean()) ** 2)
self.r2_ = 1 - ss_res / ss_tot

Worked Example

Using: Prediction:

Actual value in dataset:

Error:

Squared error:

This is how the model measures how far prediction is from truth.


Why This Algorithm Works

Simple Linear Regression assumes:

  1. the relationship is approximately linear
  2. one feature is enough to explain the target
  3. the best line is the one with minimum squared error

By minimizing squared error, the algorithm finds a line that stays as close as possible to all points overall.


Final Summary

Simple Linear Regression learns: using:

For this dataset, the learned model is: with:

So the model fits the data well and captures a strong positive linear relationship.


Exam-Oriented Points

  • Used for predicting a continuous value
  • Works with one input feature
  • Equation of model:
  • Parameters are found using the Normal Equation
  • Performance is commonly measured with
  • Best when the relationship between feature and target is approximately linear

Very Short Revision

  • Add bias column
  • Compute parameters using Normal Equation
  • Form regression line
  • Predict output
  • Evaluate using

Formula: Model: