This project implements multiple linear regression in C++ from scratch, featuring both gradient descent and the analytical normal equation solution.
This project implements linear regression two ways:
- Gradient Descent — iteratively nudges weights toward lower loss
- Normal Equation — computes the exact optimal weights in one shot using linear algebra
Both methods are implemented without any ML libraries. Everything from matrix operations to normalization is written from scratch in C++.
Given a sample with features
Our goal is to minimize this loss function.
Weights are updated each epoch by computing the gradient of the loss:
where
This process is repeated for a fixed number of epochs, or until the loss converges. It works on the principle of moving in the direction of the negative gradient to minimize the loss.
Instead of iterating, we can solve for the exact optimal weights directly. This can be done using the normal equation.
To find the optimal weights
The MSE loss function in matrix form is:
Expanding the expression:
Taking the gradient with respect to
Multiplying both sides by the inverse of
where
An
cpp-linear-regression/
├── data/
├── includes/
│ ├── regression.hpp ← LinearRegression class
│ ├── normalizer.hpp ← Z-score normalization
│ └── matrix.hpp ← Matrix class with inverse
├── src/
│ ├── regression.cc
│ ├── normalizer.cc
│ ├── matrix.cc ← Gauss-Jordan elimination
│ └── driver.cc ← Training and evaluation
└── Makefile
| Method | Description |
|---|---|
predict(x) |
Dot product of weights and input + bias |
computeLoss(X, y) |
Mean squared error |
train(X, y, lr, epochs) |
Gradient descent training loop |
trainAnalytical(X, y) |
Normal equation — exact closed-form solution |
computeR2(X, y) |
R-squared metric |
getWeights(), getBias() |
Accessors |
Implements the fit/transform pattern to prevent data leakage.
| Method | Description |
|---|---|
fit(X) |
Compute mean and std from training data only |
transform(X) |
Z-score normalize a full dataset |
transformSingle(x) |
Normalize a single sample at inference time |
Z-score formula:
Full matrix class supporting the operations needed for the normal equation.
| Method | Description |
|---|---|
multiply(B) |
Matrix multiplication |
transpose() |
Flip rows and columns |
inverse() |
Gauss-Jordan elimination on augmented matrix |
add(B) |
Element-wise addition |
scalarMultiply(s) |
Scale all elements |
Trained on
| Method | Test MSE | R² |
|---|---|---|
| Gradient Descent | ~0.19 | 0.996 |
| Normal Equation | ~0.19 | 0.996 |
Both methods converge to the same solution — the normal equation just gets there instantly.
make
./regressionRequires g++ with C++17 support.
- Multiple linear regression with vectorized operations
- Feature normalization and the fit/transform pattern to avoid data leakage
- Gradient descent with batch updates
- Matrix inverse via Gauss-Jordan elimination
- Closed-form solution vs iterative optimization — same result, different paths
- Train/test split and R² evaluation
This project is part of a series building ML components from scratch in C++:
cpp-perceptron— single-layer perceptron trained on UCI Iriscpp-linear-regression← you are herecpp-logistic-regression— logistic regression with gradient descent and normal equationcpp-neural-network— neural network with backpropagation and gradient descent