Math — Multivariate Probability
A progressive implementation of multivariate statistics — from mean vectors and covariance matrices to correlation and the multivariate normal distribution, building toward the Gaussian foundations of machine learning with NumPy.
Learning Objectives
| # | Concept |
|---|---|
| 1 | Compute the mean vector of a multivariate dataset with np.mean and axis control |
| 2 | Compute the covariance matrix manually using the sample covariance formula (no np.cov) |
| 3 | Understand Bessel's correction () for an unbiased sample covariance estimate |
| 4 | Derive the correlation matrix from covariance via diagonal scaling |
| 5 | Fit a multivariate normal distribution from data using maximum likelihood estimation |
| 6 | Compute the multivariate normal PDF using the full formula with determinant and inverse |
| 7 | Validate inputs with cascading exception checks in a specific priority order |
Data Conventions
This module uses two matrix layouts — a key learning point about data conventions in ML:
| Layout | Shape | Meaning | Used In |
|---|---|---|---|
| Samples × Features | data points, dimensions — each row is a sample | Task 0, Task 1 | |
| Features × Samples | dimensions, data points — each column is a sample | MultiNormal class |
The transpose flips between conventions. Pay attention to which axis you compute the mean along and how the covariance matrix multiplication is ordered.
Task-by-Task Reference
Each task below highlights the unique challenge it posed and the new technique introduced — techniques from earlier tasks are not repeated.
Task 0 — Mean & Covariance (0-mean_cov.py)
Challenge: Compute both the mean vector and covariance matrix of a multivariate dataset — implementing the sample covariance formula from scratch without using np.cov.
Approach: Given of shape , compute the mean with np.mean(X, axis=0, keepdims=True) to get shape . Center the data: . The sample covariance is — the matrix multiplication of the centered data's transpose with itself, scaled by Bessel's correction. Inputs are validated in order: 2D ndarray check → check.
New techniques introduced:
| Technique | Purpose |
|---|---|
np.mean(X, axis=0, keepdims=True) | Compute mean along samples axis, preserving 2D shape |
| Data centering: | Subtract the mean from every row via NumPy broadcasting |
| Sample covariance as sum of outer products divided by degrees of freedom | |
| Bessel's correction ( denominator) | Unbiased estimate — sample covariance, not population |
isinstance(X, np.ndarray) and X.ndim != 2 | Validate 2D array before any computation |
n < 2 → ValueError | Require multiple data points for meaningful covariance |
Key takeaway: The covariance matrix captures how each pair of dimensions varies together — is the covariance between dimension and dimension . Bessel's correction () gives an unbiased estimate of the population covariance. Without
keepdims=True, the mean collapses to 1D, breaking the broadcasting in the centering step.
Task 1 — Correlation Matrix (1-correlation.py)
Challenge: Convert a covariance matrix into a correlation matrix — normalizing covariances to the range so relationships between variables measured in different units become directly comparable.
Approach: Extract the diagonal variances with np.diagonal(). Compute scaling factors (element-wise power). Build a diagonal matrix from these factors with np.diagflat(). The correlation matrix is the sandwich product , which scales each covariance by .
New techniques introduced:
| Technique | Purpose |
|---|---|
np.diagonal(C) | Extract the variance vector (diagonal of covariance matrix) |
diag ** (-1/2) | Element-wise power — compute for each variance |
np.diagflat(scaling_factors) | Build a diagonal matrix from a 1D array of scaling factors |
| sandwich product | Normalize every entry: |
| Correlation always in | Standardized covariance — scale-invariant and unit-free |
Key takeaway: Correlation is standardized covariance — it strips away the units so you can compare relationships across variables measured on different scales (e.g., height in cm vs. weight in kg). The diagonal scaling trick is a clean one-liner that transforms any covariance matrix into its correlation form.
Task (class) — Multivariate Normal Distribution (multinormal.py)
Challenge: Implement a class that fits a multivariate normal distribution from data and computes the PDF for any point — combining mean, covariance, determinant, and inverse into the full multivariate Gaussian formula. This is the culmination of all multivariate probability concepts.
Approach: The constructor accepts data of shape (features × samples — note the transposed convention from Task 0). It computes the mean along axis 1 (per-feature) with keepdims=True for shape . The covariance is — note the reversed multiplication order vs. Task 0 because of the transposed layout. The pdf(x) method computes the full multivariate normal density:
using np.linalg.det() for the determinant, np.linalg.inv() for the precision matrix, and .item() to extract the scalar result from the 1×1 matrix.
New techniques introduced:
| Technique | Purpose |
|---|---|
| Class-based distribution modeling | Encapsulate parameters (mean, cov) and operations (pdf) in a reusable object |
| data convention | Features as rows, samples as columns — common in ML literature |
np.mean(data, axis=1, keepdims=True) | Compute per-feature means, yielding shape |
| for covariance | Correct multiplication order for layout |
np.linalg.det(self.cov) | Determinant — measures the "volume" of the distribution |
np.linalg.inv(self.cov) | Precision matrix — used in the Mahalanobis distance |
| Mahalanobis distance — "how many std devs away" accounting for correlations | |
.item() on 1×1 array | Extract a Python float from a NumPy array of shape |
| normalization factor | Ensures the PDF integrates to 1 over |
Key takeaway: The multivariate normal PDF generalizes the 1D Gaussian bell curve to dimensions. The covariance matrix controls the shape (spread) and orientation (correlation) of the bell. The Mahalanobis distance inside the exponent measures distance accounting for correlations — points on the same density contour have the same Mahalanobis distance. The determinant in the normalization scales the peak height: larger determinant → more spread → lower peak.
Technique Inventory
| Task | New technique summarized | Category |
|---|---|---|
| 0 | np.mean with axis/keepdims, data centering, Bessel's correction , covariance via | Mean & Covariance |
| 1 | np.diagonal(), np.diagflat(), sandwich, correlation = covariance ÷ (std × std) | Correlation |
| class | Class-based distribution, layout, np.linalg.det/inv, Mahalanobis distance, multivariate PDF formula | Multivariate Normal |
Multivariate Probability Pipeline
Data X ──→ Mean μ ──→ Covariance Σ ──→ Correlation P ──→ MultiNormal(μ, Σ) ──→ PDF(x)
(n×d) (1×d) (d×d) (d×d) class scalar
- Mean locates the center of the data in -dimensional space
- Covariance captures the spread and pairwise relationships
- Correlation standardizes to for interpretability
- MultiNormal packages mean and covariance into a full probability distribution
- PDF answers: "how likely is this point under the fitted distribution?"