How Ridge Regression Prevents Overfitting with L2 Regularization: A Complete Guide

Ridge regression prevents overfitting by adding an L2 penalty term (λ‖w‖²₂) to the loss function, which shrinks coefficient magnitudes toward zero and stabilizes the solution when features are collinear or the data matrix is ill-conditioned.

This article examines the mechanics of ridge regression as implemented in the rohitg00/ai-engineering-from-scratch repository, breaking down how L2 regularization constrains model complexity to improve generalization. We analyze the closed-form mathematical solution, explore its Bayesian interpretation, and provide runnable Python code from the curriculum's linear systems implementation.

The L2 Regularization Mechanism

Ridge regression augments ordinary least squares (OLS) with a Tikhonov regularization term that penalizes the squared magnitude of the weight vector. The optimization objective transforms from minimizing squared error to minimizing:


‖Xw - y‖²₂ + λ‖w‖²₂

Here, λ (lambda) controls the regularization strength. As implemented in phases/01-math-foundations/17-linear-systems/code/linear_systems.py, this modification changes the normal equations from XᵀXw = Xᵀy to (XᵀX + λI)w = Xᵀy, where I is the identity matrix.

Three Ways L2 Regularization Reduces Overfitting

1. Coefficient Shrinkage

The penalty term λ‖w‖²₂ forces the optimization algorithm to balance fitting the training data against keeping weights small. Large coefficient values incur higher costs, so the solution favors weight vectors with smaller magnitudes distributed across features. This shrinkage reduces the model's capacity to fit noise in the training data, directly addressing the high-variance component of overfitting.

2. Improved Matrix Conditioning

In phases/01-math-foundations/17-linear-systems/code/linear_systems.py, the implementation explicitly adds lam * np.eye(A.shape[1]) to the Gram matrix A.T @ A. This addition of λI along the diagonal:

  • Increases the smallest eigenvalues of the matrix
  • Makes the matrix symmetric positive-definite
  • Stabilizes numerical inversion when features are highly correlated (multicollinearity)

Without regularization (λ = 0), near-singular matrices cause unstable, high-magnitude weights that overfit. The L2 term guarantees invertibility and numerical stability.

3. Bias-Variance Trade-off

Ridge regression intentionally introduces a small bias to substantially reduce variance. While OLS provides unbiased estimates, ridge regression's shrinkage creates slightly biased coefficient estimates. However, in high-dimensional spaces or with correlated features, this bias dramatically lowers prediction variance on unseen data, yielding lower overall generalization error according to the convex optimization theory documented in phases/01-math-foundations/18-convex-optimization/docs/en.md.

Bayesian Interpretation of Ridge Regression

As detailed in phases/01-math-foundations/07-bayes-theorem/docs/en.md, ridge regression corresponds to Maximum A Posteriori (MAP) estimation under a Gaussian prior. When you assume weights follow a zero-mean Gaussian distribution with variance proportional to 1/λ, the MAP estimate exactly matches the ridge regression solution. This probabilistic perspective frames L2 regularization as principled prior knowledge that extreme weight values are unlikely, naturally discouraging overfitting without requiring explicit feature selection.

Implementation: From-Scratch Ridge Regression

The curriculum provides a pure NumPy implementation in phases/01-math-foundations/17-linear-systems/code/linear_systems.py. The ridge_regression function demonstrates the closed-form solution:

import numpy as np
from sklearn.linear_model import Ridge as SklearnRidge
from sklearn.metrics import r2_score

# Synthetic data generation

np.random.seed(0)
X = np.random.randn(100, 3)
true_w = np.array([1.5, -2.0, 0.5])
y = X @ true_w + 0.1 * np.random.randn(100)

def ridge_regression(A, b, lam):
    """
    Solve ridge regression via normal equations.
    Returns w that minimizes ||Aw - b||^2 + lam*||w||^2
    """
    # (AᵀA + λI) w = Aᵀb

    return np.linalg.solve(A.T @ A + lam * np.eye(A.shape[1]), A.T @ b)

# Fit with regularization strength λ = 0.1

lam = 0.1
w_ridge = ridge_regression(X, y, lam)
print("Ridge weights:", np.round(w_ridge, 4))

This implementation explicitly constructs the regularized normal equations, solving (AᵀA + λI)w = Aᵀb using np.linalg.solve for numerical stability.

Validating with Scikit-Learn

To verify the from-scratch implementation matches production libraries, the code compares against scikit-learn's Ridge class:


# Scikit-learn comparison

ridge_sk = SklearnRidge(alpha=lam, fit_intercept=False)
ridge_sk.fit(X, y)
print("sklearn weights:", np.round(ridge_sk.coef_, 4))

# Verify equivalence

diff = np.max(np.abs(w_ridge - ridge_sk.coef_))
print("Maximum difference:", diff)

# Demonstrate overfitting prevention

w_ols = ridge_regression(X, y, 0.0)  # No regularization

print("\nOLS weights (λ=0):", np.round(w_ols, 4))
print("R² (ridge):", r2_score(y, X @ w_ridge))
print("R² (OLS):  ", r2_score(y, X @ w_ols))

The comparison demonstrates that the manual implementation produces identical results to scikit-learn while providing transparency into how the L2 penalty (A.T @ A + lam * np.eye(...)) modifies the optimization landscape.

Summary

  • Ridge regression adds λ‖w‖²₂ to the loss function, penalizing large weights through L2 regularization.
  • The modification (XᵀX + λI) improves matrix conditioning, solving multicollinearity and numerical instability issues present in OLS.
  • Coefficient shrinkage reduces model variance at the cost of small bias, improving generalization on unseen data.
  • The technique corresponds to MAP estimation with a Gaussian prior, providing a Bayesian justification for the penalty term.
  • The rohitg00/ai-engineering-from-scratch repository implements this in phases/01-math-foundations/17-linear-systems/code/linear_systems.py using np.linalg.solve for the regularized normal equations.

Frequently Asked Questions

What is the difference between L1 and L2 regularization?

L2 regularization (ridge) penalizes the sum of squared weights (‖w‖²₂), shrinking coefficients smoothly toward zero but rarely exactly to zero. L1 regularization (Lasso) penalizes the sum of absolute weights (‖w‖₁), which can drive coefficients exactly to zero and perform feature selection. Ridge regression maintains all features with reduced magnitudes, while Lasso performs implicit feature selection.

How do I choose the optimal lambda (α) value for ridge regression?

Select λ through cross-validation, typically k-fold validation. Iterate over a logarithmic grid of λ values (e.g., 10⁻⁴ to 10⁴), fitting ridge regression on training folds and evaluating mean squared error on validation folds. The λ yielding the lowest validation error minimizes the bias-variance trade-off. Scikit-learn's RidgeCV automates this grid search.

Does ridge regression eliminate features like Lasso?

No. Ridge regression shrinks coefficients toward zero but does not set them exactly to zero (unless λ approaches infinity). It performs coefficient shrinkage rather than feature selection. If you require sparse models with feature elimination, use Lasso (L1) or Elastic Net, which combine L1 and L2 penalties as referenced in the convex optimization documentation.

Can ridge regression handle multicollinearity?

Yes. Ridge regression specifically addresses multicollinearity by adding λ to the diagonal of XᵀX, which increases the smallest eigenvalues and ensures the matrix remains invertible even when features are highly correlated. This stabilization prevents the explosive variance in coefficient estimates that occurs with ordinary least squares when predictor variables are collinear.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →